home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Technotools
/
Technotools (Chestnut CD-ROM)(1993).ISO
/
lang_asm
/
asm_kit
/
kermit.asm
< prev
next >
Wrap
Assembly Source File
|
1985-08-05
|
171KB
|
5,471 lines
.XLIST
;******************** Version 1.20 *********************************
; [20] (a) When in terminal emulation, if host sends an ESC-Z to
; identify the terminal type being used, respond with "ESC / K".
; (b) Allow ^X/^Z to interrupt sending a file or file group,
; respectively. (c) Ditto to interrupt receiving a file or file
; group. (d) If get an error when receiving a file, clean up
; and send an error packet. Allow user to specify whether to
; keep what made it over or to discard it. (e) Before sending a
; packet, clear the input buffer. (f) Use one general routine
; to send all error packets. (g) Add U. of Arizona changes so
; Kermit once again compiles on the Z100 (Joellen Windsor). Move
; IBM specific statements inside IBM conditional assembly blocks.
; Daphne, 11/28/83
;******************** Version 1.19A *********************************
; [19] (a) Change NOUT to print numbers in decimal instead of hex.
; Routine is based on the one used in Generic Kermit. Make a
; cosmetic change where print filenames & remove extraneous screen
; output. Add "nop" in NAK because the jump to ABORT is only
; 2 bytes. Change ONTAB so the valid values are in alphabetical
; order. Also, keep only one copy of the code that sets the baud
; rate and prints it's value. (b) Allow users to choose between
; COM1 (default) and COM2. Also, remind the user about which
; communications port they are using and at what baud rate when
; connecting to another system. (c) Add SET BACKARROW so can
; set backarrow to backspace or delete. (William Dair) Also,
; set default to ON for renaming files due to filename conflicts.
; (d) When connecting to host, only bump up cursor if on line 25.
; (e) Clean up parsing error messages. Change VT52 emulation
; messages to Heath-19.
; Daphne, 10/21/83
;******************** Version 1.18 **********************************
; [18] A NAK for the next packet is not the same as an ACK for the
; current packet if we're in Send-Init. Also, account for
; wraparound when comparing packet numbers that are off by one.
; Daphne, 7/13/83
;******************** Version 1.3A **********************************
; [17] (a) Make command to SET BELL ON/OFF when transfer is complete.
; Changed variable name to be consistent with other flags.
; (b) Make it more like a Heath/Zenith H19 (I/D L/C,inverse,24x80).
; (c) Fix Telflg to be in CS so Telnet works.
; Dave King (CMU), 7/1/83
;******************** Version 1.3 **********************************
; [16] Make adjustments to XT changes so that things that used to work
; still do: pass along characters with the eighth bit on, and in
; OUTCHR, don't overwrite character after setting the appropriate
; parity.
; Daphne, 6/17/83
; [15] Add tabs stop and clear screen support. Don't give checksum
; warnings. Give keyboard input higher scheduling priority than
; port input. This allows users to ^S, ^O, ^C, etc. the output
; when the port is full of characters. Add a CMU conditional
; to swap control-backspace (delete) with backspace since TOPS-20
; and VMS are more delete than backspace oriented.
; Glenn Marcy, 6/8/83
; [14] Add CMU changes that allow Kermit to work on the XT. Plus add
; a statement omitted previously when comparing packet numbers.
; Daphne, 5/26/83 (changes by Dave King, CMU)
;******************** Version 1.2 **********************************
; [13] When closing received file, handle case where number of bytes is
; divisible by 128.
; Daphne, 5/2/83
;******************** Version 1.1 **********************************
; [12] If "SET IBM", set local echo, XON/XOFF, and default (mark) parity.
; Daphne, 4/15/83
; [11] In RPACK, don't push packet type, but store in temp variable.
; If push and get an error, you pick up packet type as return addr.
; Daphne, 4/15/83
; [10] Add Set Parity Command.
; Daphne, 4/12/83
; [9] Allow single-character wildcard in filenames, use "=".
; Daphne, 4/4/83
; [8] Add Kermit server support.
; Daphne, 3/17/83
; [7] Allow wildcards in filename.
; Daphne, 3/15/83
; [6] Make format of "Set Escape" look like the other commands.
; Daphne, 3/14/83
; [5] Add Set "End-of-Line" (to the char used to terminate packets I send).
; Daphne, 3/7/83
; [4] Ring bell when done (when succeed and when fail).
; Daphne, 2/10/83
; [3] Match keyword if "?" is the terminator.
; Daphne, 2/9/83
; [2] Change "Inpkt" so ignores bare CR from any system.
; Daphne, 2/9/83
; [1] Add "cmer04" - print error message if run off list of commands allowed.
; Daphne, 2/9/83
;******************** Version 1.0 **********************************
; KERMIT - KL10 Error-free Reciprocal Micro Interconnect over TTY-lines
;
; Program Version 1.20, Kermit Protocol Version 2
; November 4, 1983
;
; Based on the KERMIT Protocol.
;
; Copyright (C) 1982,1983 Trustees of Columbia University
;
; Daphne Tzoar
; Columbia University Computer Center
; 612 W. 115th St.
; New York City, NY 10025
;
; Special thanks to Frank da Cruz, Bill Catchings, Steve Jensen,
; Vace Kundakci, and Bernie Eiben for their help and contributions.
; This file is the global data area for all the Kermit modules.
CMU EQU 0 ; CMU conditional assembly. [15]
IBMPC EQU 1 ; For IBM PC conditional assembly.
Z100 EQU 0 ; For Heath/Zenith Z-100.
STEVE EQU 0 ; For Steve's homebrew assembly.
BELL EQU 07Q
TAB EQU 11Q
LF EQU 12Q
FF EQU 14Q
CR EQU 15Q
XON EQU 21Q
XOFF EQU 23Q
ESC EQU 33Q
DEL EQU 177Q
BS EQU 08H
DOS EQU 21H
CONIN EQU 01H
CONOUT EQU 02H
RDRIN EQU 03H
PUNOUT EQU 04H
LSTOUT EQU 05H
DCONIO EQU 06H
GTIOB EQU 07H
PRSTR EQU 09H
CONSTAT EQU 0BH
OPENF EQU 0FH
CLOSF EQU 10H
SFIRST EQU 11H
SNEXT EQU 12H
DELF EQU 13H
READF EQU 14H ; Read from the file.
WRITEF EQU 15H
MAKEF EQU 16H
SETDMA EQU 1AH
CFLSZ EQU 23H
MAXPKT EQU '~'-' '+2Q ; Maximum size of a packet.
MAXTRY EQU 05Q ; Default number of retries on a packet.
IMXTRY EQU 20Q ; Default number of retries send initiate.
DRPSIZ EQU 5EH ; Default receive packet size.
DSPSIZ EQU 20H ; Default send packet size.
DSTIME EQU 08H ; Default send time out interval.
DRTIME EQU 05H ; Default receive time out interval.
DSPAD EQU 00H ; Default send padding.
DRPAD EQU 00H ; Default receive padding.
DSPADC EQU 00H ; Default send padding char.
DRPADC EQU 00H ; Default receive padding char.
DSEOL EQU CR ; Default send EOL char.
DREOL EQU CR ; Default receive EOL char.
DSQUOT EQU '#' ; Default send quote char.
DRQUOT EQU '#' ; Default receive quote char.
PAREVN EQU 00H ; Even parity. [10 start]
PARMRK EQU 01H ; Mark parity.
PARNON EQU 02H ; No parity.
PARODD EQU 03H ; Odd parity.
PARSPC EQU 04H ; Space parity.
DEFPAR EQU PARNON ; Default parity (none.)
IBMPAR EQU PARMRK ; IBM's parity (mark.) [10 end]
SOH EQU 01H ; Start of header char.
BUFSIZ EQU 80H ; Size of DMA.
DIASW EQU 01H ; Default is diagnostics on.
CMKEY EQU 01H ; Parse a keyword.
CMIFI EQU 02H ; Parse an input file spec (can be wild).
CMOFI EQU 03H ; Parse an output file spec.
CMCFM EQU 04H ; Parse a confirm.
CMTXT EQU 05H ; Parse arbitrary text up to CR. [8]
IF ibmpc
BIOS EQU 10H
COMM EQU 14H
KEYB EQU 16H
DEFESC EQU ']'-100Q ; The default escape character.
MDMDAT1 EQU 03F8H ; Address of modem port (data). [19b]
MDMSTS1 EQU 03FDH ; Address of modem port status. [19b]
MDMCOM1 EQU 03FBH ; Address of modem port command. [19b]
MDMDAT2 EQU 02F8H ; Port 2 address. [19b]
MDMSTS2 EQU 02FDH ; Port 2 status. [19b]
MDMCOM2 EQU 02FBH ; Port 2 command. [19b]
MDMINP EQU 1 ; Input ready bit.
BRKBIT EQU 040H ; Send-break bit. [20g]
MDMINTV EQU 0030H ; Address of modem port interrupt vector.
MDINTV2 EQU 002CH ; Address for port 2. [19b]
MDMINTO EQU 0EFH ; Mask to enable interrupt for modem port.
MDINTO2 EQU 0F7H ; Enable interrupt level 3. [19b]
MDMINTC EQU 010H ; Bit to set to disable interrupts for modem.
MDINTC2 EQU 008H ; Disable IRQ3. [19b]
INTCONT EQU 0021H ; Address of 8259 interrupt controller ICW2-3.
INTCON1 EQU 0020H ; Address of 8259 ICW1.
EOICOM EQU 0064H ; End of interrupt.
EOICOM2 EQU 0063H ; End of interrupt for COM2. [19b]
TIMER EQU 40H ; Use to issue short beep.
PORT_B EQU 61H ; Port B address.
B0300 EQU 180H ; Variables for 300 baud, 1200, etc.
B1200 EQU 60H
B1800 EQU 40H
B2400 EQU 30H
B4800 EQU 18H
B9600 EQU 0CH
ENDIF
IF Z100
MDMCOM EQU 0EFH ; Asynch port command register. [20g]
BRKBIT EQU 048H ; Send-break bits. [20g]
DEFESC EQU '\'-100Q ; The default escape character.
; BIOS entry points
BIOS_SEG SEGMENT AT 40H ; Define segment where BIOS really is
ORG 6*3
BIOS_AUXOUT LABEL FAR ; AUX output routine
ORG 26*3
BIOS_AUXFUNC LABEL FAR ; AUX: function
BIOS_SEG ENDS ; End of BIOS segment defs
; Function codes for BIOS_AUXFUNC
CHR_READ EQU 1 ; Read character
CHR_STATUS EQU 2 ; Get status
CHR_SFGS EQU 0 ; Get status subfunction
CHR_SFGC EQU 1 ; Get config subfunction
CHR_CONTROL EQU 3 ; Control function
CHR_CFSU EQU 0 ; Set new configuration parameters
B00455 EQU 0 ; 45.5 baud
B0050 EQU 1 ; 50 baud
B0075 EQU 2 ; 75 baud
B0110 EQU 3 ; 110 baud
B01345 EQU 4 ; 134.5 baud
B0150 EQU 5 ; 150 baud
B0300 EQU 6 ; 300 baud
B0600 EQU 7 ; 600 baud
B1200 EQU 8 ; 1200 baud
B1800 EQU 9 ; 1800 baud
B2000 EQU 10 ; 2000 baud
B2400 EQU 11 ; 2400 baud
B4800 EQU 12 ; 4800 baud
B9600 EQU 13 ; 9600 baud
B19200 EQU 14 ; 19200 baud
B38400 EQU 15 ; 38400 baud
ENDIF
STACK SEGMENT PARA STACK 'STACK'
DW 100 DUP(0) ; Initialize stack to all zeros.
STK EQU THIS WORD
STACK ENDS
DATAS SEGMENT PARA PUBLIC 'DATAS'
; Pure storage.
versio db 'CUCCA'
IF ibmpc
db ' IBM-PC'
ENDIF
IF Z100
db '/Stevens Heath/Zenith Z-100'
ENDIF
db ' Kermit-86 - ver 1.20',cr,lf,'$' ;[19a]
kerm db 'Kermit-86>$'
spmes db 'Spack: $'
rpmes db 'Rpack: $'
hibit db 'Warning - Non Ascii char$'
tmp db ?
foo db '$'
crlf db cr,lf,'$'
ender db bell,bell,'$' ; [4]
tmsg1 db cr,lf,'[Connecting to host, type $'
tmsg3 db ' C to return to PC$' ; [17b, 19b]
tmsg2 db cr,lf,'[Back at micro]',cr,lf,'$'
tmsg4 db ', connecting over port COM$' ; [19b]
ermes1 db cr,lf,'?Unregonized command$'
ermes2 db cr,lf,'?Illegal character$'
ermes3 db cr,lf,'?Not confirmed$'
ermes4 db 'Unable to rename file$'
ermes7 db '?Unable to receive initiate$'
ermes8 db '?Unable to receive file name$'
ermes9 db '?Unable to receive end of file$'
erms10 db '?Unable to receive data$'
erms11 db '?Disk full$'
erms14 db '?Unable to receive an acknowledgement from the host$'
erms15 db '?Unable to find file$'
erms17 db 'Record length exceeds size of buffer$'
erms18 db cr,lf,'?Unable to tell host that session is finished$'
erms19 db cr,lf,'?Unable to tell host to logout$'
infms0 db 'Waiting .....$'
infms1 db 'Receiving ...$'
infms2 db 'Sending .....$'
infms3 db 'Completed $'
infms4 db 'Failed $'
infms5 db 'Renaming file to $'
infms6 db 'Interrupted $' ; [20b]
infms7 db 'File interrupt: OK $' ; [20b]
infms8 db 'File group interrupt: OK $' ; [20b]
cfrmes db ' Confirm with carriage return $'
filhlp db ' Input file spec (possibly wild) $'
esctl db 'Control-$' ; [6]
spchar db 24H,26H,23H,40H,21H,25H,27H,28H,29H,2DH
db 3CH,3EH,7BH,7DH,5FH,5CH,5EH,7EH,7CH,60H
eschlp db cr,lf,'Enter literal value (ex: Cntrl ]) $'
tophlp db cr,lf,'BYE to host (LOGOUT) and exit to DOS'
db cr,lf,'CONNECT to host on selected port'
db cr,lf,'EXIT to DOS'
db cr,lf,'FINISH running Kermit on the host'
db cr,lf,'HELP by giving this message'
db cr,lf,'LOGOUT the host'
db cr,lf,'RECEIVE file from host'
db cr,lf,'SEND file to host'
db cr,lf,'SET a parameter'
; db cr,lf,'SHOW the parameters'
db cr,lf,'STATUS of Kermit$'
sethlp db cr,lf,'BACKARROW to' ; [19c]
db cr,lf,'BAUD rate'
db cr,lf,'BELL' ; [17a]
db cr,lf,'DEBUG'
db cr,lf,'END-OF-LINE character'
db cr,lf,'ESCAPE character change'
db cr,lf,'FILE-WARNING'
IF ibmpc
db cr,lf,'HEATH-19' ; [19e]
ENDIF
db cr,lf,'IBM'
db cr,lf,'INCOMPLETE file' ; [20d]
db cr,lf,'LOCAL-ECHO echoing (half-duplex)'
db cr,lf,'PARITY type' ; [10]
IF ibmpc
db cr,lf,'PORT for communication$' ; [19b]
; db cr,lf,'VT52-EMULATION$' ; [19e]
ENDIF
IF Z100
db '$'
ENDIF
stshlp db cr,lf,'PAD-CHAR'
db cr,lf,'PADDING$'
onhlp db cr,lf,'OFF ON$'
yeshlp db cr,lf,'NO YES$'
abfhlp db cr,lf,'DISCARD KEEP$' ; [20d]
comphlp db cr,lf,'1 (COM1) 2 (COM2)$' ; [19b]
parhlp db cr,lf,'None Mark Odd Even Space$' ; [10]
IF ibmpc
bdhlp db cr,lf,'300 1200 1800 2400 4800 9600$'
ENDIF
IF Z100
bdhlp db cr,lf,'45.5 50 75 110 134.5 150 300'
db ' 600 1200 1800'
db cr,lf,' 2000 2400 4800 9600 19200 38400'
ENDIF
BShlp db cr,lf,'BACKSPACE DELETE$' ; [19c]
eolhlp db cr,lf,'Decimal digit between 0 and 31$' ; [5]
eolerr db cr,lf,'Illegal end-of-line character$' ; [5]
inthlp db cr,lf,'? This message'
db cr,lf,'C Close the connection'
db cr,lf,'S Status of the connection'
db cr,lf,'B Send a break' ; [20g]
db cr,lf,'Typing the escape character will send it to the host'
db cr,lf,cr,lf,'Command>$'
locst db cr,lf,'Local echo on$'
remst db cr,lf,'Local echo off$'
belon db cr,lf,'Ring bell at end of transfer$' ; [17a - DT]
beloff db cr,lf,'No bell at end of transfer$' ; [17a - DT]
IF ibmpc
vtemst db cr,lf,'HEATH-19 emulation on$' ; [19e]
novtst db cr,lf,'HEATH-19 emulation off$' ; [19e]
cm1st db cr,lf,'Using communications port 1$' ; [19b]
cm2st db cr,lf,'Using communications port 2$' ; [19b]
ENDIF
ibmst db cr,lf,'IBM on$'
noibm db cr,lf,'IBM off$'
pnonst db cr,lf,'No parity$' ; [10]
poddst db cr,lf,'Odd parity$' ; [10]
pevnst db cr,lf,'Even parity$' ; [10]
pmrkst db cr,lf,'Mark parity$' ; [10]
pspcst db cr,lf,'Space parity$' ; [10]
IF Z100
b04st db cr,lf,'Baud rate is 45.5$'
b05st db cr,lf,'Baud rate is 50$'
b07st db cr,lf,'Baud rate is 75$'
b11st db cr,lf,'Baud rate is 110$'
b13st db cr,lf,'Baud rate is 134.5$'
b15st db cr,lf,'Baud rate is 150$'
b06st db cr,lf,'Baud rate is 600$'
b20st db cr,lf,'Baud rate is 2000$'
b19st db cr,lf,'Baud rate is 19200$'
b38st db cr,lf,'Baud rate is 38400$'
ENDIF
b03st db cr,lf,'Baud rate is 300$'
b12st db cr,lf,'Baud rate is 1200$'
b18st db cr,lf,'Baud rate is 1800$'
b24st db cr,lf,'Baud rate is 2400$'
b48st db cr,lf,'Baud rate is 4800$'
b96st db cr,lf,'Baud rate is 9600$'
debon db cr,lf,'Debug mode on$'
deboff db cr,lf,'Debug mode off$'
flwon db cr,lf,'File Warning on$'
flwoff db cr,lf,'File Warning off$'
bkbs db cr,lf,'Backarrow sends a backspace $' ; [19c]
bkdel db cr,lf,'Backarrow sends a delete $' ; [19c]
abfdst db cr,lf,'Discard incoming file if incomplete $' ;[20d]
abfkst db cr,lf,'Keep incoming file if incomplete $' ;[20d]
eolst db cr,lf,'End-of-line character is ^$' ; [5]
escmes db cr,lf,'Escape character is $' ; [6]
outlin db cr,lf,' CUCCA'
IF ibmpc
db ' IBM-PC'
ENDIF
IF Z100
db '/Stevens Heath/Zenith Z-100'
ENDIF
db ' Kermit-86 V1.20',cr,lf
db cr,lf,'Number of packets: ' ; [19a]
db cr,lf,'Number of retries: ' ; [19a]
db cr,lf,'File name $'
delstr db 10O,' ',10O,10O,'$' ; Delete string.
clrspc db ' ',10O,'$' ; Clear space.
escspc db 10O,' ',10O,'$' ; Clear escape.
IF ibmpc
clrlin db cr,'$' ; Clear line (just the cr part).
ENDIF
IF Z100
clrlin db cr,esc,'K$' ; Clear line on Z-100
clreol db esc,'K$' ; Clear to end of line
clrscr db esc,'H',esc,'J$' ; Home and clear screen
homcur db esc,'H$' ; Home cursor
ENDIF
prsp db ' $' ; Print a space.
; Cursor addressing items.
IF ibmpc
scrhi dw 0434H ; Err when 8th bit is on.
scrrpr dw 0700H ; Prompt when Kermit ends.
screrr dw 0600H ; Place for error msgs.
scrfln dw 050CH ; Place for file name.
scrnrt dw 0415H ; Place for number of retries.
scrnp dw 0315H ; Place for number of packets.
scrfr dw 0600H ; Rename file.
scrst dw 0334H ; Place for status.
scrint dw 0434H ; Acknowledge interrupt. [20b]
scrsp dw 0800H ; Place for send packet.
scrrp dw 0A00H ; Place for receive packet.
ttab label word ; Table for cursor movement.
ta dw curup ; Cursor up.
tb dw curdwn ; Cursor down.
tc dw currt ; Cursor right.
td dw curlft ; Cursor left.
te dw curclr ; Clear display. [15]
tf dw curskp ; Enter graphics mode.
tg dw curskp ; Exit graphics mode.
th dw curhm ; Cursor home.
ti dw curup ; Reverse line feed.
tj dw curscr ; Clear to end of screen.
tk dw curln ; Clear to end of line.
tl dw inslin ; Insert line.
tm dw dellin ; Delete line.
tn dw delchr ; Delete character. [17b]
to dw insmox ; Cancel Insert Character. [17b]
ENDIF
IF Z100
scrhi db esc,'Y',23H,54H,lf,'$' ; 8th bit on in character
scrrpr db esc,'Y',27H,20H,'$' ; Prompt when Kermit ends
screrr db esc,'Y',26H,20H,'$' ; Error messages
scrfln db esc,'Y',25H,2CH,'$' ; File name
scrnrt db esc,'Y',23H,35H,lf,'$' ; Number of retries
scrnp db esc,'Y',23H,35H,'$' ; Number of packets
scrfr db esc,'Y',26H,20H,'$' ; Rename file
scrst db esc,'Y',23H,54H,'$' ; Status
scrint db esc,'Y',24H,54H,'$' ; Acknowledge interrupt. [20b]
scrsp db esc,'Y',28H,20H,'$' ; send packet
scrrp db esc,'Y',2AH,20H,'$' ; Receive packet
ENDIF
; COMND tables
comtab db 0AH ; Ten entries.
db 03H,'BYE$'
dw bye
db 07H,'CONNECT$'
dw telnet
db 04H,'EXIT$'
dw exit
db 06H,'FINISH$'
dw finish
db 04H,'HELP$'
dw help
db 06H,'LOGOUT$'
dw logout
db 07H,'RECEIVE$'
dw read
db 04H,'SEND$'
dw send
db 03H,'SET$'
dw setcom
db 06H,'STATUS$'
dw status
IF ibmpc
settab db 0DH ; Thirteen entries. [17a][19b][19c][20d]
ENDIF
IF Z100
settab db 0BH ; Eleven entries. [10][17a][19c][20d]
ENDIF
db 09H,'BACKARROW$' ; [19c]
dw BSset ; [19c]
db 04H,'BAUD$'
dw baudst
db 04H,'BELL$' ; [17a]
dw bellst ; [17a]
db 05H,'DEBUG$'
dw debst
db 0BH,'END-OF-LINE$' ; [5]
dw eolset ; [5]
db 06H,'ESCAPE$'
dw escape
db 0CH,'FILE-WARNING$'
dw filwar
IF ibmpc
db 0DH,'H19-EMULATION$' ; [19e]
dw vt52em ; [19e]
ENDIF
db 03H,'IBM$'
dw ibmset
db 0AH,'INCOMPLETE$' ; [20d]
dw abfset ; [20d]
db 0AH,'LOCAL-ECHO$'
dw lcal
db 06H,'PARITY$' ; [10]
dw setpar ; [10]
IF ibmpc
db 04H,'PORT$' ; [19b]
dw comset ; [19b]
; db 0EH,'VT52-EMULATION$' ; [19e]
; dw vt52em ; [19e]
ENDIF
ontab db 02H ; Two entries.
db 03H,'OFF$' ; Should be alphabetized. [19a]
dw 00H
db 02H,'ON$'
dw 01H
; If abort when receiving files, can keep what we have or discard. [20d]
abftab db 02H ; Only two options.
db 07H,'DISCARD$'
dw 01H
db 04H,'KEEP$'
dw 00H
; Entries for choosing communications port. [19b]
comptab db 04H
db 01H,'1$'
dw 01H
db 01H,'2$'
dw 00H
db 04H,'COM1$'
dw 01H
db 04H,'COM2$'
dw 00H
yestab db 02H ; Two entries.
db 02H,'NO$'
dw 00H
db 03H,'YES$'
dw 01H
partab db 05H ; Five entries. [10 start]
db 04H,'EVEN$'
dw PAREVN
db 04H,'MARK$'
dw PARMRK
db 04H,'NONE$'
dw PARNON
db 03H,'ODD$'
dw PARODD
db 05H,'SPACE$'
dw PARSPC ;[10 end]
BStab db 02H ;Two entries [19c start]
db 09H,'BACKSPACE$'
dw 00H
db 06H,'DELETE$'
dw 01H ;[19c]
IF ibmpc
bdtab db 06H ; Six entries.
db 04H,'1200$'
dw B1200
db 04H,'1800$'
dw B1800
db 04H,'2400$'
dw B2400
db 03H,'300$'
dw B0300
db 04H,'4800$'
dw B4800
db 04H,'9600$'
dw B9600
ENDIF
IF Z100
bdtab db 010H ; 16 entries
db 03H,'110$'
dw b0110
db 04H,'1200$'
dw b1200
db 03H,'134$'
dw b01345
db 03H,'150$'
dw b0150
db 04H,'1800$'
dw b1800
db 05H,'19200$'
dw b19200
db 04H,'2000$'
dw b2000
db 04H,'2400$'
dw b2400
db 03H,'300$'
dw b0300
db 05H,'38400$'
dw b38400
db 02H,'45$'
dw b00455
db 04H,'4800$'
dw b4800
db 02H,'50$'
dw b0050
db 03H,'600$'
dw b0600
db 02H,'75$'
dw b0075
db 04H,'9600$'
dw b9600
ENDIF
; COMND storage
cmer00 db cr,lf,'?Program error Invalid COMND call$'
cmer01 db cr,lf,'?Ambiguous$'
cmer02 db cr,lf,'?Illegal input file spec$'
;cmer03 db cr,lf,'?Unrecognized instruction$'
cmer03 db cr,lf,'?Invalid command$' ; [19e]
cmer04 db cr,lf,'?Invalid command or operand$' ; [1]
cmin00 db ' Confirm with carriage return$'
cmcrlf db cr,lf,'$'
cmstat db ? ; What is presently being parsed.
cmaflg db ? ; Non-zero when an action char has been found.
cmccnt db ? ; Non-zero if a significant char is found.
cmsflg db ? ; Non-zero when the last char was a space.
cmostp dw ? ; Old stack pointer for reparse.
cmrprs dw ? ; Address to go to on reparse.
cmprmp dw ? ; Address of prompt.
cmptab dw ? ; Address of present keyword table.
cmhlp dw ? ; Address of present help.
cmdbuf db 80H DUP(?) ; Buffer for command parsing.
cmfcb dw ? ; Pointer to FCB.
cmfcb2 dw ? ; Pointer to position in FCB.
cmcptr dw ? ; Pointer for next char input.
cmdptr dw ? ; Pointer into the command buffer.
cmsiz dw ? ; Size info of user input.
cmkptr dw ? ; Pointer to keyword.
cmsptr dw ? ; Place to save a pointer.
cmchr db ? ; Save char when checking ambiguity.
; Program storage.
oldstk dw ? ; Storage for system stack.
oldsts dw ? ; System stack segment.
ssp dw 0 ; Save SP in Telnet.
bufhex dw 80H
filsiz dd 0 ; Double word for filesize (in bytes.)
eoflag db ? ; EOF flag; non-zero on EOF.
wldflg db 0 ; Assume no "*" in fn. [7]
;telflg db 0 ; Are we acting as a terminal. [16] [17c]
belflg db 1 ; Use bell [17a -- DT]
comflg db 1 ; Use COM1 by default. [19b]
cxzflg db 0 ; ^X/^Z to interrupt file x-fer. [20b]
abfflg db 1 ; Discard incoming file if abort. [20d]
debug db 0 ; Debugging mode (default off).
hierr db 0 ; Non-ascii char (non-zero if yes).
filflg db ? ; Non-zero when nothing in DMA buffer.
ecoflg db 0 ; Local echo flag (default off).
parflg db defpar ; Parity flag (default none.) [10]
escflg db 0 ; Escape flag (start off).
IF ibmpc
vtflg db 1 ; VT52 emulation flag (default on).
incmod db 0 ; Insert Character mode. [17b] [20g]
curatt dw 0007H ; Video attributes. [17b]
baud dw B4800 ; Use default of 4800.
mddat dw MDMDAT1 ; Default to port 1. [19b start]
mdstat dw MDMSTS1 ; Ditto.
mdcom dw MDMCOM1 ; Here too.
mden db MDMINTO
mddis db MDMINTC
mdmeoi db EOICOM
mdintv dw MDMINTV ; [19b end]
ENDIF
IF Z100
auxcnf db 4 dup(?) ; AUX port configuration info
baud db ? ; Baud rate
auxcnf1 db 12 dup(?) ; Rest of configuration info
mdcom dw MDMCOM ; Use to send a break. [20g]
ENDIF
flwflg db 1 ; File warning flag (default on). [19c]
ibmflg db 0 ; IBM flag (default off).
delflg db 1 ; Do BS to DEL translation. [19c]
extflg db 0 ; Exit flag (default off).
escchr db defesc ; Storage for the escape character.
incnt dw ? ; Number of chars read in from port.
chrcnt dw ? ; Number of chars in the file buffer.
filcnt dw ? ; Number of chars left to fill.
outpnt dw ? ; Position in packet.
bufpnt dw ? ; Position in file buffer.
fcbptr dw ? ; Position in FCB.
datptr dw ? ; Position in packet data buffer.
cbfptr dw ? ; Position in character buffer.
pktptr dw ? ; Poistion in receive packet.
siz dw ? ; Size of data from gtchr.
spsiz db dspsiz ; Send packet size.
rpsiz db drpsiz ; Receive packet size.
stime db dstime ; Send time out.
rtime db drtime ; Receive time out.
spad db dspad ; Send padding.
rpad db drpad ; Receive padding.
spadch db dspadc ; Send padding char.
rpadch db drpadc ; Receive padding char.
seol db dseol ; Send EOL char.
reol db dreol ; Receive EOL char.
squote db dsquot ; Send quote char.
rquote db drquot ; Receive quote char.
pktnum dw ? ; Packet number.
numpkt dw ? ; Total number of packets sent.
numrtr dw ? ; Total number of retries.
numtry db ? ; Number of tries on this packet.
oldtry db ? ; Number of tries on previous packet.
state db ? ; Present state of the automaton.
savsci dw ? ; Save for serial port interrupt vector. [14]
savscs dw ? ; Ditto. [14]
packet db ?,?,?,? ; Packet (data is part of it).
data db 5AH DUP(?) ; Data and checksum field of packet.
recpkt db 60H DUP(?) ; Receive packet storage (use the following).
filbuf db 60H DUP(?) ; Character buffer.
fcb db 25H DUP(?) ; Use as our FCB.
cpfcb db 25H DUP(?) ; Save FCB in case of "*". [7]
buff db 80H DUP(?) ; Use as our DAT.
rdbuf db 80H DUP(?)
cnt dw 0
temp dw 0
temp1 dw ? ; Temporary storage.
temp2 dw ?
temp3 dw ?
temp4 dw ?
argblk dw ? ; For subroutine arguments.
argbk1 dw ?
argbk2 dw ?
argbk3 dw ?
DATAS ENDS ; End data segment
MAIN SEGMENT PARA PUBLIC 'MAIN'
START PROC FAR
ASSUME CS:MAIN,DS:DATAS,SS:STACK,ES:NOTHING
push ds ; Save system data area.
sub ax,ax ; Get a zero.
push ax ; Put zero return addr on stack.
mov ax,datas ; Initialize DS.
mov ds,ax
sub ax,ax
mov oldstk,sp ; Save old stack pointer.
call cmblnk ; Clear the screen.
call locate
mov ah,prstr ; Print the version header.
mov dx,offset versio
int dos
mov ah,setdma ; Set disk transfer address.
mov dx,offset buff
int dos
call dobaud ; Set the baud rate. [19a, 20g]
; This is the main KERMIT loop. It prompts for and gets the users commands.
kermit: mov dx,offset kerm
call prompt ; Prompt the user.
mov dx,offset comtab
mov bx,offset tophlp
mov ah,cmkey
call comnd
jmp kermt2
call bx ; Call the routine returned.
jmp kermt3
cmp extflg,0 ; Check if the exit flag is set.
jne krmend ; If so jump to KRMEND.
jmp kermit ; Do it again.
kermt2: mov ah,prstr
mov dx,offset ermes1 ; Give an error.
int dos
jmp kermit
kermt3: mov ah,prstr
mov dx,offset ermes3 ; Give an error.
int dos
jmp kermit
krmend:
mov sp,oldstk
ret
START ENDP
; These are some utility routines.
; Abort
ABORT PROC NEAR
mov state,'A' ; Otherwise abort.
ret
ABORT ENDP
; NAK
NAK PROC NEAR
mov ax,pktnum ; Get the packet number we're waiting for.
mov argblk,ax
mov argbk1,0
mov ah,'N' ; NAK that packet.
call spack
jmp abort
nop ; So 'jmp rskp' in SPACK comes here. [19a]
ret ; Go around again.
NAK ENDP
; Position cursor for an error message.
ERPOS PROC NEAR
IF ibmpc
mov ah,2
mov bh,0
mov dx,screrr
int bios
ret
ENDIF
IF Z100
mov dx,offset screrr ; Get address of string to position cursor
mov ah,prstr ; Get the function code
int dos ; Print the addressing string
ret ; And return
ENDIF
ERPOS ENDP
; Position cursor for number of retries message.
RTPOS PROC NEAR
IF ibmpc
mov ah,2
mov bh,0
mov dx,scrnrt
int bios
ret
ENDIF
IF Z100
mov ah,prstr ; Get the function to print string
mov dx,offset scrnrt ; Get the address of the string
int dos ; Print the string
ret ; And return
ENDIF
RTPOS ENDP
; Reassure user that we acknowledge his ^X/^Z. [20b]
INTMSG PROC NEAR
IF ibmpc ; Tell user we acknowledge it.
mov ah,2
mov dx,scrint
mov bh,0
int bios
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrint ; and string to move cursor
int dos ; Print the string
ENDIF
mov dx,offset infms7 ; File interrupted?
cmp cxzflg,'X' ; Yes.
je int0
mov dx,offset infms8 ; File group interrupted.
int0: mov ah,prstr
int dos
ret
INTMSG ENDP
; Print err message that found a non-standard-Ascii char in the file.
BITERR PROC NEAR
push bx
IF ibmpc
mov ah,2
mov bh,0
mov dx,scrhi
int bios
ENDIF
IF Z100
mov ah,prstr ; Get the function to print string
mov dx,offset scrhi ; Get the address of the string
int dos ; Print the string
ENDIF
mov ah,prstr
mov dx,offset hibit
int dos
pop bx
ret
BITERR ENDP
; This routine prints out the escape character in readable format.
ESCPRT PROC NEAR ; [6 start]
mov dl,escchr
cmp dl,' '
jge escpr2
push dx
mov ah,prstr
mov dx,offset esctl
int dos
pop dx
add dl,040H ; Make it printable.
escpr2: mov ah,conout
int dos
ret
ESCPRT ENDP ; [6 end]
; FCB must be remembered if found "*" in filename. [7 start]
; Copy from place addressed by BX to place addressed by DI.
; Also use to get the filename to the FCB from the DTA.
FCBCPY PROC NEAR
fcbcp1: cmp cl,0
je fcbcp2
mov ah,[bx]
mov [di],ah
dec cl
inc bx
inc di
jmp fcbcp1
fcbcp2: ret
FCBCPY ENDP
; This routine sets up the data for init packet (either the
; Send_init or ACK packet).
RPAR PROC NEAR
mov ah,rpsiz ; Get the receive packet size.
add ah,' ' ; Add a space to make it printable.
mov [bx],ah ; Put it in the packet.
mov ah,rtime ; Get the receive packet time out.
add ah,' ' ; Add a space.
mov 1[bx],ah ; Put it in the packet.
mov ah,rpad ; Get the number of padding chars.
add ah,' '
mov 2[bx],ah ; Put it in the packet.
mov ah,rpadch ; Get the padding char.
add ah,100O ; Uncontrol it.
and ah,7FH
mov 3[bx],ah ; Put it in the packet.
mov ah,reol ; Get the EOL char.
add ah,' '
mov 4[bx],ah ; Put it in the packet.
mov ah,rquote ; Get the quote char.
mov 5[bx],ah ; Put it in the packet.
mov ah,06H ; Six pieces of data.
ret
RPAR ENDP
; This routine reads in all the send_init packet information.
SPAR PROC NEAR
mov temp4,ax ; Save the number of arguments.
mov ah,[bx] ; Get the max packet size.
sub ah,' ' ; Subtract a space.
mov spsiz,ah ; Save it.
mov ax,temp4
cmp al,3 ; Fewer than three pieces?
jge spar1
ret ; If so we are done.
spar1: mov ah,2[bx] ; Get the number of padding chars.
sub ah,' '
mov spad,ah
mov ax,temp4
cmp al,4 ; Fewer than four pieces?
jge spar2
ret ; If so we are done.
spar2: mov ah,3[bx] ; Get the padding char.
add ah,100O ; Re-controlify it.
and ah,7FH
mov spadch,ah
mov ax,temp4
cmp al,5 ; Fewer than five pieces?
jge spar3
ret ; If so we are done.
spar3: mov ah,4[bx] ; Get the EOL char.
sub ah,' '
mov seol,ah
mov ax,temp4
cmp al,6 ; Fewer than six pieces?
jge spar4
ret ; If so we are done.
spar4: mov ah,5[bx] ; Get the quote char.
mov squote,ah
ret
SPAR ENDP
; Initialize buffers and clear line.
INIT PROC NEAR
call cmblnk
call locate
mov ah,prstr ; Put statistics headers on the screen.
mov dx,offset outlin
int dos
call init1
ret
INIT ENDP
INIT1 PROC NEAR
mov chrcnt,bufsiz ; Number of chars left.
mov bufpnt,offset buff ; Addr for beginning.
ret
INIT1 ENDP
; Clear out message about interrupted file. [20b]
CXMSG PROC NEAR
IF ibmpc
mov ah,2
mov bh,0
mov dx,scrint
int bios
mov ax,0920H
mov bx,7
mov cx,26
int bios
ret
ENDIF
IF Z100
mov ah,prstr
mov dx,offset scrint ; Move the cursor.
int dos
mov ah,prstr ; Get the function again
mov dx,offset clreol ; And the sequence to clear to EOL
int dos ; Do it
ret
ENDIF
CXMSG ENDP
; Clear out the old filename on the screen.
CLRFLN PROC NEAR
IF ibmpc
mov ah,2
mov bh,0
mov dx,scrfln
int bios
call clreol ; Clear to end of line. [19a]
ret
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrfln ; and string to move cursor
int dos ; Print the string
mov ah,prstr ; Get the function again
mov dx,offset clreol ; And the sequence to clear to EOL
int dos ; Do it
ret ; And return
ENDIF
CLRFLN ENDP
; RECEIVE command
READ PROC NEAR
mov bx,offset data ; Where to put text (if any). [8 start]
mov ah,cmtxt
call comnd ; Get text or confirm.
jmp kermt3
cmp ah,0 ; Read in any chars?
je read1 ; A regular receive.
mov al,ah
mov ah,0
mov argbk1,ax ; Remember number of chars we read.
mov ah,'$' ; Use for printing.
mov [bx],ah
call init ; Clear line and initialize buffers.
call clrfln ; Prepare to print filename.
mov ah,prstr
mov dx,offset data ; Print file name.
int dos
mov argblk,0 ; Start at packet zero.
mov ah,'R' ; Receive init packet.
call spack ; Send the packet.
jmp kermt3
jmp read12 ; [8 end]
read1: call init ; Clear the line and initialize the buffers.
read12: mov numpkt,0 ; Set the number of packets to zero.
mov numrtr,0 ; Set the number of retries to zero.
mov pktnum,0 ; Set the packet number to zero.
mov numtry,0 ; Set the number of tries to zero.
mov cxzflg,0 ; Reset ^X/^Z flag. [20c]
call serini ; Initialize serial port. [14]
call rtpos ; Position cursor.
mov ax,numrtr
call nout ; Write the number of retries.
mov state,'R' ; Set the state to receive initiate.
read2:
IF ibmpc
mov ah,2 ; Position cursor.
mov dx,scrst
mov bh,0
int bios
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrst ; and string to move cursor
int dos ; Print the string
ENDIF
mov ah,prstr ; Be informative.
mov dx,offset infms1
int dos
IF ibmpc
mov ah,2
mov dx,scrnp
mov bh,0
int bios
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrnp ; and string to move cursor
int dos ; Print the string
ENDIF
mov ax,numpkt
call nout ; Write the number of packets.
mov ah,state ; Get the state.
cmp ah,'D' ; Are we in the data send state?
jne read3
call rdata
jmp read2
read3: cmp ah,'F' ; Are we in the file receive state?
jne read4
call rfile ; Call receive file.
jmp read2
read4: cmp ah,'R' ; Are we in the receive initiate state?
jne read5
call rinit
jmp read2
read5: cmp ah,'C' ; Are we in the receive complete state?
jne read6
call serrst ; Reset serial port. [14]
IF ibmpc
mov ah,2 ; Position cursor.
mov dx,scrst
mov bh,0
int bios
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrst ; and string to move cursor
int dos ; Print the string
ENDIF
mov ah,prstr
mov dx,offset infms3 ; Plus a little cuteness.
cmp cxzflg,0 ; Completed or interrupted? [20c]
je read13 ; Ended normally. [20c]
mov dx,offset infms6 ; Say was interrupted. [20c]
read13: int dos
cmp belflg,0 ; Bell desired? [17a]
je readnb ; No. [17a]
mov dx,offset ender ; Ring them bells. [4]
int dos ; [4]
readnb: ; [17a -- new label]
IF ibmpc
mov ah,2
mov dx,scrrpr ; Put prompt here.
mov bh,0
int bios
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrrpr ; and string to move cursor
int dos ; Print the string
ENDIF
jmp rskp
read6: call serrst ; Reset serial port. [14]
IF ibmpc
mov ah,2 ; Position cursor.
mov dx,scrst
mov bh,0
int bios
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrst ; and string to move cursor
int dos ; Print the string
ENDIF
mov ah,prstr
mov dx,offset infms4 ; Plus a little cuteness.
int dos
cmp belflg,0 ; Bell desired? [17a]
je read7 ; No. [17a]
mov dx,offset ender ; Ring them bells. [4]
int dos ; [4]
read7:
IF ibmpc
mov ah,2
mov dx,scrrpr
mov bh,0
int bios
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrrpr ; and string to move cursor
int dos ; Print the string
ENDIF
jmp rskp
READ ENDP
; Receive routines
; Receive init
RINIT PROC NEAR
mov ah,numtry ; Get the number of tries.
cmp ah,imxtry ; Have we reached the maximum number of tries?
jl rinit2
call erpos ; Position cursor.
mov dx,offset ermes7
mov ah,prstr
int dos ; Print an error message.
jmp abort ; Change the state to abort.
rinit2: inc ah ; Increment it.
mov numtry,ah ; Save the updated number of tries.
call rpack ; Get a packet.
jmp nak ; Trashed packet: nak, retry.
cmp ah,'S' ; Is it a send initiate packet?
jne rinit3 ; If not see if its an error.
mov ah,numtry ; Get the number of tries.
mov oldtry,ah ; Save it.
mov numtry,0 ; Reset the number of tries.
mov ax,argblk ; Returned packet number. (Synchronize them.)
inc ax ; Increment it.
and ax,3FH ; Turn off the two high order bits.
mov pktnum,ax ; Save modulo 64 of the number.
mov bx,numpkt
inc bx ; Increment the number of packets.
mov numpkt,bx
mov ax,argbk1 ; Get the number of arguments received.
mov bx,offset data ; Get a pointer to the data.
call spar ; Get the data into the proper variables.
mov bx,offset data ; Get a pointer to our data block.
call rpar ; Set up the receive parameters.
xchg ah,al
mov ah,0
mov argbk1,ax ; Store the returned number of arguments.
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
mov ah,'F' ; Set the state to file send.
mov state,ah
ret
rinit3: cmp ah,'E' ; Is it an error packet?
jne rinit4
call error
rinit4: jmp abort
RINIT ENDP
; Receive file
RFILE PROC NEAR
cmp numtry,maxtry ; Have we reached the maximum number of tries?
jl rfile1
call erpos ; Position cursor.
mov dx,offset ermes8
mov ah,prstr
int dos ; Print an error message.
jmp abort ; Change the state to abort.
rfile1: inc numtry ; Save the updated number of tries.
call rpack ; Get a packet.
jmp nak ; Trashed packet: nak, retry.
cmp ah,'S' ; Is it a send initiate packet?
jne rfile2 ; No, try next type.
cmp oldtry,imxtry ; Have we reached the maximum number of tries?
jl rfil12 ; If not proceed.
call erpos ; Position cursor.
mov dx,offset ermes7
mov ah,prstr
int dos ; Print an error message.
jmp abort ; Change the state to abort.
rfil12: inc oldtry ; Save the updated number of tries.
mov ax,pktnum ; Get the present packet number.
cmp ax,0 ; Had we wrapped around? [18 start]
jne rfilx
mov ax,64
rfilx: dec ax ; Decrement. [18 end -- new label]
cmp ax,argblk ; Is the packet's number one less than now?
je rfil13
jmp nak ; No, NAK and try again.
rfil13: call rtpos ; Position cursor.
inc numrtr ; Increment the number of retries.
mov ax,numrtr
call nout ; Write the number of retries.
mov numtry,0 ; Reset the number of tries.
mov bx,offset data ; Get a pointer to our data block.
call rpar ; Set up the parameter information.
xchg ah,al
mov ah,0
mov argbk1,ax ; Save the number of arguments.
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
ret
rfile2: cmp ah,'Z' ; Is it an EOF packet?
jne rfile3 ; No, try next type.
cmp oldtry,maxtry ; Have we reached the maximum number of tries?
jl rfil21 ; If not proceed.
call erpos ; Position cursor.
mov dx,offset ermes9
mov ah,prstr
int dos ; Print an error message.
jmp abort ; Change the state to abort.
rfil21: inc oldtry ; Increment it.
mov ax,pktnum ; Get the present packet number.
cmp ax,0 ; Had we wrapped around? [18 start]
jne rfily
mov ax,64
rfily: dec ax ; Decrement. [18 end -- new label]
cmp ax,argblk ; Is the packet's number one less than now?
je rfil24
jmp nak ; No, NAK and try again.
rfil24: call rtpos ; Position cursor.
inc numrtr ; Increment the number of retries
mov ax,numrtr
call nout ; Write the number of retries.
mov numtry,0
mov argbk1,0 ; No data. (The packet number is in argblk.)
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
ret
rfile3: cmp ah,'F' ; Start of file?
jne rfile4
mov ax,argblk ; Get the packet number.
cmp ax,pktnum ; Is it the right packet number?
je rfil32
jmp nak ; No, NAK it and try again.
rfil32: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pktnum,ax ; Save modulo 64 of the number.
inc numpkt ; Increment the number of packets.
call gofil ; Get a file to write to.
jmp abort
call init1 ; Initialize all the buffers.
mov ah,numtry ; Get the number of tries.
mov oldtry,ah ; Save it.
mov numtry,0 ; Reset the number of tries.
mov argbk1,0 ; No data. (The packet number is in argblk.)
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
mov state,'D' ; Set the state to data receive.
ret
rfile4: cmp ah,'B' ; End of transmission.
jne rfile5
mov ax,pktnum
cmp ax,argblk ; Do we match?
je rfil41
jmp nak ; No, NAK it and try again.
rfil41: mov argbk1,0 ; No data. (Packet number already in argblk).
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
mov state,'C' ; Set the state to complete.
ret
rfile5: cmp ah,'E' ; Is it an error packet.
jne rfile6
call error
rfile6: jmp abort
RFILE ENDP
; Receive data
RDATA PROC NEAR
cmp numtry,maxtry ; Get the number of tries.
jl rdata1
call erpos ; Position cursor.
mov dx,offset erms10
mov ah,prstr
int dos ; Print an error message.
jmp abort ; Change the state to abort.
rdata1: inc numtry ; Save the updated number of tries.
call rpack ; Get a packet.
jmp nak ; Trashed packet: nak, retry.
cmp ah,'D' ; Is it a data packet?
je rdat11
jmp rdata2 ; No, try next type.
rdat11: mov ax,pktnum ; Get the present packet number.
cmp ax,argblk ; Is the packet's number correct?
jz rdat14
cmp oldtry,maxtry ; Have we reached the maximum number of tries?
jl rdat12 ; If not proceed.
call erpos ; Position cursor.
mov dx,offset erms10
mov ah,prstr
int dos ; Print an error message.
jmp abort ; Change the state to abort.
rdat12: inc oldtry ; Save the updated number of tries.
; dec pktnum ; Decrement present packet number. [14]
mov ax,pktnum
cmp ax,0 ; Had we wrapped around? [18 start]
jne rdatx
mov ax,64
rdatx: dec ax ; [14] [18 end -- new label]
cmp ax,argblk ; Is the packet's number one less than now?
je rdat13
jmp nak ; No, NAK it and try again.
rdat13: call rtpos ; Position cursor.
inc numrtr ; Increment the number of retries
mov ax,numrtr
call nout ; Write the number of retries.
mov numtry,0 ; Reset number of tries.
mov argbk1,0 ; No data. (The packet number is in argblk.)
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
ret
rdat14: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pktnum,ax ; Save modulo 64 of the number.
inc numpkt ; Increment the number of packets.
mov ah,numtry ; Get the number of tries.
mov oldtry,ah ; Save it.
mov ax,argbk1 ; Get the length of the data.
cmp cxzflg,0 ; Has the user typed a ^X or ^Z? [20c]
jne rdat15 ; If yes don't write data out to file. [20c]
call ptchr
jmp abort ; Unable to write out chars; abort.
rdat15: mov numtry,0 ; Reset the number of tries.
mov argbk1,0 ; No data. (Packet number still in argblk.)
cmp cxzflg,0 ; Interrupt file transfer? [20c]
je rdat16 ; Nope. [20c]
mov bx,offset data ; Send data in ACK in case remote... [20c]
mov ah,cxzflg ; ... knows about ^X/^Z. [20c]
mov [bx],ah ; Put data into the packet. [20c]
mov argbk1,1 ; Set data size to 1. [20c]
rdat16: mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
ret
rdata2: cmp ah,'F' ; Start of file?
jne rdata3 ; No, try next type.
cmp oldtry,maxtry ; Have we reached the maximum number of tries?
jl rdat21 ; If not proceed.
call erpos ; Position cursor.
mov dx,offset ermes8
mov ah,prstr
int dos ; Print an error message.
jmp abort ; Change the state to abort.
rdat21: inc oldtry ; Save the updated number of tries.
mov ax,pktnum
cmp ax,0 ; Had we wrapped around? [18 start]
jne rdaty
mov ax,64
rdaty: dec ax ; [14 Omitted accidentally - D.T.] [18 end]
cmp ax,argblk ; Is the packet's number one less than now?
je rdat22
jmp nak ; No, NAK it and try again.
rdat22: call rtpos ; Position cursor.
inc numrtr ; Increment the number of retries
mov ax,numrtr
call nout ; Write the number of retries.
mov numtry,0 ; Reset number of tries.
mov argbk1,0 ; No data. (The packet number is in argblk.)
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
ret
rdata3: cmp ah,'Z' ; Is it a EOF packet?
je rdat3x ; [13]
jmp rdata4 ; Try and see if its an error. [13]
rdat3x: mov ax,pktnum ; Get the present packet number. [13]
cmp ax,argblk ; Is the packet's number correct?
je rdat32
jmp nak ; No, NAK it and try again.
rdat32: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pktnum,ax ; Save modulo 64 of the number.
inc numpkt
cmp cxzflg,0 ; Do we want to discard the file? [20c]
jne rdt32x ; Yes. [20c]
cmp argbk1,1 ; One piece of data? [20c]
jne rdat33 ; Nope - finish writing out file? [20c]
mov bx,offset data ; Get data area. [20c]
mov ah,[bx] ; Get the data. [20c]
cmp ah,'D' ; "D" for discard? [20c]
jne rdat33 ; Nope - write out file. [20c]
rdt32x: mov ah,delf ; Delete the file if opened. [20c]
mov dx,offset fcb ; Give the file parameters. [20c]
int dos ; Kill it, ignore errors. [20c]
cmp cxzflg,'X' ; Kill one file or all? [20c]
jne rdat36 ; No so leave flag alone. [20c]
call cxmsg ; Clear msg about interrupt. [20c]
mov cxzflg,0 ; Reset - ^X only kills one file. [20c]
jmp rdat36
rdat33: mov bx,bufpnt ; Get the dma pointer.
mov ax,80H
sub ax,chrcnt ; Get the number of chars left in the DMA.
cmp ax,80H ; [13 start]
jne rdat34
call outbuf ; Write out buffer if no room for ^Z.
jmp abort
mov ax,0 ; [13 end]
rdat34: mov cl,'Z'-100O ; Put in a ^Z for EOF.
mov [bx],cl
inc ax
dec chrcnt
mov cx,chrcnt
mov temp,cx
inc bx
rdt3: inc ax
cmp ax,80H
jg rdat35 ; Pad till full.
mov cl,0 ; Use nulls.
mov [bx],cl
inc bx
jmp rdt3
rdat35: call outbuf ; Output the last buffer.
jmp abort ; Give up if the disk is full.
call fixfcb
mov ah,closf ; Close up the file.
mov dx,offset fcb
int dos
rdat36: mov ah,numtry ; Get the number of tries.
mov oldtry,ah ; Save it.
mov numtry,0 ; Reset the number of tries.
mov argbk1,0 ; No data. (The packet number is in argblk.)
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
mov state,'F'
ret
rdata4: cmp ah,'E' ; Is it an error packet.
jne rdata5
call error
rdata5: jmp abort
RDATA ENDP
FIXFCB PROC NEAR
mov bx,offset fcb+18
mov di,offset filsiz
mov ax,[bx]
mov [di],ax
mov bx,offset fcb+16
mov ax,[bx]
mov 2[di],ax
mov ax,temp ; Get number of chars in last buffer full.
sub filsiz+2,ax ; Get real file size.
sbb filsiz,0
mov bx,offset fcb+18
mov di,offset filsiz
mov ax,[di]
mov [bx],ax
mov bx,offset fcb+16
mov ax,2[di]
mov [bx],ax
ret
FIXFCB ENDP
; Send command
SEND PROC NEAR
mov ah,cmifi ; Parse an input file spec.
mov dx,offset fcb ; Give the address for the FCB.
call comnd
jmp r ; Give up on bad parse.
send1: mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
send11: mov ah,sfirst ; Get the first file.
mov dx,offset fcb
int dos
cmp al,0FFH ; Any found?
jne send12
mov ah,prstr
mov dx,offset crlf
int dos
mov ah,prstr
mov dx,offset erms15
int dos
ret
send12: cmp wldflg,0 ; Any wildcards. [7 start]
je send16 ; Nope, so no problem.
mov bx,offset fcb ; Remember what FCB looked like.
mov di,offset cpfcb
mov cl,37 ; Size of FCB.
call fcbcpy
mov di,offset fcb+1 ; Copy filename from DTA to FCB.
mov bx,offset buff+1
mov cl,11
call fcbcpy ; [7 end]
send16: call init ; Clear the line and initialize the buffers.
call serini ; Initialize serial port. [14]
mov pktnum,0 ; Set the packet number to zero.
mov numtry,0 ; Set the number of tries to zero.
mov numpkt,0 ; Set the number of packets to zero.
mov numrtr,0 ; Set the number of retries to zero.
call rtpos ; Position cursor.
mov ax,0
call nout ; Write the number of retries.
mov state,'S' ; Set the state to receive initiate.
send2:
IF ibmpc
mov ah,2 ; Position cursor.
mov bh,0
mov dx,scrst
int bios
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrst ; and string to move cursor
int dos ; Print the string
ENDIF
mov ah,prstr ; Be informative.
mov dx,offset infms2
int dos
IF ibmpc
mov ah,2
mov dx,scrnp
mov bh,0
int bios
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrnp ; and string to move cursor
int dos ; Print the string
ENDIF
mov ax,numpkt
call nout ; Write the packet number.
cmp state,'D' ; Are we in the data send state?
jne send3
call sdata
jmp send2
send3: cmp state,'F' ; Are we in the file send state?
jne send4
call sfile ; Call send file.
jmp send2
send4: cmp state,'Z' ; Are we in the EOF state?
jne send5
call seof
jmp send2
send5: cmp state,'S' ; Are we in the send initiate state?
jne send6
call sinit
jmp send2
send6: cmp state,'B' ; Are we in the eot state?
jne send7
call seot
jmp send2
send7: cmp state,'C' ; Are we in the send complete state?
jne send8
call serrst ; Reset serial port. [14]
IF ibmpc
mov ah,2 ; Position cursor.
mov dx,scrst
mov bh,0
int bios
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrst ; and string to move cursor
int dos ; Print the string
ENDIF
mov ah,prstr
mov dx,offset infms3 ; Plus a little cuteness.
cmp cxzflg,0 ; Completed or interrupted? [20b]
je snd71 ; Ended normally. [20b]
mov dx,offset infms6 ; Say was interrupted. [20b]
snd71: int dos ; New label. [20b]
cmp belflg,0 ; Bell desired? [17a]
je sendnb ; [17a]
mov dx,offset ender ; Ring them bells. [4]
int dos ; [4]
sendnb: ; [17a -- new label]
IF ibmpc
mov ah,2
mov dx,scrrpr
mov bh,0
int bios
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrrpr ; and string to move cursor
int dos ; Print the string
ENDIF
jmp rskp
send8: call serrst ; Reset serial port. [14]
IF ibmpc
mov ah,2 ; Position cursor.
mov dx,scrst
mov bh,0
int bios
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrst ; and string to move cursor
int dos ; Print the string
ENDIF
mov ah,prstr
mov dx,offset infms4 ; Plus a little cuteness.
int dos
cmp belflg,0 ; Bell desired? [17a]
je send9 ; No. [17a]
mov dx,offset ender ; Ring them bells. [4]
int dos ; [4]
send9:
IF ibmpc
mov ah,2
mov dx,scrrpr
mov bh,0
int bios
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrrpr ; and string to move cursor
int dos ; Print the string
ENDIF
jmp rskp
SEND ENDP
; Send routines
; Send initiate
SINIT PROC NEAR
cmp numtry,imxtry ; Have we reached the maximum number of tries?
jl sinit2
call erpos
mov dx,offset erms14
mov ah,prstr
int dos ; Print an error message.
jmp abort ; Change the state to abort.
sinit2: inc numtry ; Save the updated number of tries.
mov bx,offset data ; Get a pointer to our data block.
call rpar ; Set up the parameter information.
xchg ah,al
mov ah,0
mov argbk1,ax ; Save the number of arguments.
mov ax,numpkt ; Get the packet number.
mov argblk,ax
mov ah,'S' ; Send initiate packet.
call spack ; Send the packet.
jmp abort
call rpack ; Get a packet.
jmp r ; Trashed packet don't change state, retry.
cmp ah,'Y' ; ACK?
jne sinit3 ; If not try next.
mov ax,pktnum ; Get the packet number.
cmp ax,argblk ; Is it the right packet number?
je sini22
ret ; If not try again.
sini22: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pktnum,ax ; Save modulo 64 of the number.
inc numpkt ; Increment the number of packets.
mov ax,argbk1 ; Get the number of pieces of data.
mov bx,offset data ; Pointer to the data.
call spar ; Read in the data.
mov ah,numtry ; Get the number of tries.
mov oldtry,ah ; Save it.
mov numtry,0 ; Reset the number of tries.
mov state,'F' ; Set the state to file send.
call getfil ; Open the file.
jmp abort ; Something is wrong, die.
ret
sinit3: cmp ah,'N' ; NAK?
jne sinit4 ; If not see if its an error.
call rtpos ; Position cursor.
inc numrtr ; Increment the number of retries
mov ax,numrtr
call nout ; Write the number of retries.
; mov ax,pktnum ; Get the present packet number. [18 start]
; inc ax ; Increment.
; cmp ax,argblk ; Get the packet's number.
; je sini32
; ret ; If not assume its for this packet, go again.
;sini32: mov numtry,0 ; Reset number of tries.
; mov state,'F' ; Set the state to file send. [18 end]
ret
sinit4: cmp ah,'E' ; Is it an error packet.
jne sinit5
call error
sinit5: jmp abort
SINIT ENDP
; Send file header
SFILE PROC NEAR
cmp numtry,maxtry ; Have we reached the maximum number of tries?
jl sfile1
call erpos
mov dx,offset erms14
mov ah,prstr
int dos ; Print an error message.
jmp abort ; Change the state to abort.
sfile1: inc numtry ; Increment it.
mov cxzflg,0 ; Clear ^X,^Z flag. [20b]
mov datptr,offset data ; Get a pointer to our data block.
mov bx,offset fcb+1 ; Pointer to file name in FCB.
mov fcbptr,bx ; Save position in FCB.
mov cl,0 ; Counter for chars in file name.
mov ch,0 ; Counter for number of chars in FCB.
sfil11: cmp ch,8H ; Ninth char?
jne sfil12
mov ah,'.'
mov bx,datptr
mov [bx],ah ; Put dot in data packet.
inc bx
mov datptr,bx ; Save new position in data packet.
inc cl
sfil12: inc ch
cmp ch,0CH ; Twelve?
jns sfil13
mov bx,fcbptr
mov ah,[bx] ; Get char of filename.
inc bx
mov fcbptr,bx ; Save position in FCB.
cmp ah,'!' ; Is it a good char?
jl sfil11 ; If not, get the next.
mov bx,datptr
mov [bx],ah ; Put char in data buffer.
inc cl ; Increment counter.
inc bx
mov datptr,bx ; Save new position.
jmp sfil11 ; Get another char.
sfil13: mov ch,0
mov argbk1,cx ; Save number of char in filename.
mov bx,datptr
mov ah,'$'
mov [bx],ah ; Put dollar sign for printing.
call clrfln
mov ah,prstr
mov dx,offset data ; Print file name.
int dos
mov ax,pktnum ; Get the packet number.
mov argblk,ax
mov ah,'F' ; File header packet.
call spack ; Send the packet.
jmp abort
call rpack ; Get a packet.
jmp r ; Trashed packet don't change state, retry.
cmp ah,'Y' ; ACK?
jne sfile2 ; If not try next.
mov ax,pktnum ; Get the packet number.
cmp ax,argblk
je sfil14
ret ; If not hold out for the right one.
sfil14: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pktnum,ax ; Save modulo 64 of the number.
inc numpkt ; Increment the number of packets.
mov ah,numtry ; Get the number of tries.
mov oldtry,ah ; Save it.
mov numtry,0 ; Reset the number of tries.
sfil15: mov ah,0 ; Get a zero.
mov bx,offset fcb
add bx,20H
mov [bx],ah ; Set the record number to zero.
mov eoflag,ah ; Indicate not EOF.
mov ah,0FFH
mov filflg,ah ; Indicate file buffer empty.
call gtchr
jmp sfil16 ; Error go see if its EOF.
jmp sfil17 ; Got the chars, proceed.
sfil16: cmp ah,0FFH ; Is it EOF?
je sfl161
jmp abort ; If not give up.
sfl161: mov ah,'Z' ; Set the state to EOF.
mov state,ah
ret
sfil17: mov siz,ax
mov state,'D' ; Set the state to data send.
ret
sfile2: cmp ah,'N' ; NAK?
jne sfile3 ; Try if error packet.
call rtpos ; Position cursor.
inc numrtr ; Increment the number of retries
mov ax,numrtr
call nout ; Write the number of retries.
mov ax,pktnum ; Get the present packet number.
inc ax ; Increment.
and ax,03FH ; Account for wraparound. [18]
cmp ax,argblk ; Is the packet's number one more than now?
jz sfil14 ; Just as good as a ACK; go to the ACK code.
ret ; If not go try again.
sfile3: cmp ah,'E' ; Is it an error packet.
jne sfile4
call error
sfile4: jmp abort
SFILE ENDP
; Send data
SDATA PROC NEAR
cmp cxzflg,0 ; Have we seen ^X or ^Z? [20b]
je sdata0 ; Nope, just continue. [20b]
mov state,'Z' ; Else, abort sending the file. [20b]
ret
sdata0: cmp numtry,maxtry ; Have we reached the maximum number of tries?
jl sdata1
call erpos
mov dx,offset erms14
mov ah,prstr
int dos ; Print an error message.
jmp abort ; Change the state to abort.
sdata1: inc numtry ; Increment it.
mov datptr,offset data ; Get a pointer to our data block.
mov cbfptr,offset filbuf ; Pointer to chars to be sent.
mov cx,1 ; First char.
sdat11: mov bx,cbfptr
mov ah,[bx]
inc cbfptr
mov bx,datptr
mov [bx],ah ; Put the char in the data packet.
inc datptr ; Save position in data packet.
inc cx ; Increment the count.
cmp cx,siz ; Have we transfered that many?
jle sdat11 ; If not get another.
mov ax,siz ; Number of char in char buffer.
mov argbk1,ax
mov ax,pktnum ; Get the packet number.
mov argblk,ax
mov ah,'D' ; Data packet.
call spack ; Send the packet.
jmp abort
call rpack ; Get a packet.
jmp r ; Trashed packet don't change state, retry.
cmp ah,'Y' ; ACK?
jne sdata2 ; If not try next.
mov ax,pktnum ; Get the packet number.
cmp ax,argblk ; Is it the right packet number?
jz sdat12
ret ; If not hold out for the right one.
sdat12: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pktnum,ax ; Save modulo 64 of the number.
inc numpkt ; Increment the number of packets.
mov ah,numtry ; Get the number of tries.
mov oldtry,ah ; Save it.
mov numtry,0 ; Reset the number of tries.
cmp argbk1,1 ; Does the ACK contain data? [20b]
jne sdt12x ; Nope, so continue. [20b]
mov bx,offset data ; If yes, check the data field. [20b]
mov ah,[bx] ; Pick it up. [20b]
cmp ah,'X' ; Other side requests ^X? [20b]
jne sdt12y ; Nope. [20b]
jmp sdt12z ; And leave. [20b]
sdt12y: cmp ah,'Z' ; Other side requests ^Z? [20b]
jne sdt12x ; Nope. [20b]
sdt12z: mov cxzflg,ah ; Yes remember it. [20b]
mov state,'Z' ; Abort sending file(s). [20b]
ret
sdt12x: call gtchr
jmp sdat13 ; Error go see if its EOF.
mov siz,ax ; Save the size of the data gotten.
ret
sdat13: cmp ah,0FFH ; Is it EOF?
je sdt131
jmp abort ; If not give up.
sdt131: mov state,'Z' ; Set the state to EOF.
ret
sdata2: cmp ah,'N' ; NAK?
jne sdata3 ; See if is an error packet.
call rtpos ; Position cursor.
inc numrtr ; Increment the number of retries
mov ax,numrtr
call nout ; Write the number of retries.
mov ax,pktnum ; Get the present packet number.
inc ax ; Increment.
and ax,03FH ; Account for wraparound. [18]
cmp ax,argblk ; Is the packet's number one more than now?
jz sdat12 ; Just as good as ACK; goto ACK code.
ret ; If not go try again.
sdata3: cmp ah,'E' ; Is it an error packet.
jne sdata4
call error
sdata4: jmp abort
SDATA ENDP
; Send EOF
SEOF PROC NEAR
cmp numtry,maxtry ; Have we reached the maximum number of tries?
jl seof1
call erpos ; Position cursor.
mov dx,offset erms14
mov ah,prstr
int dos ; Print an error message.
jmp abort ; Change the state to abort.
seof1: inc numtry ; Increment it.
mov ax,pktnum ; Get the packet number.
mov argblk,ax
mov argbk1,0 ; No data.
cmp cxzflg,0 ; Seen a ^X or ^Z? [20b]
je seof11 ; Nope, send normal EOF packet. [20b]
mov bx,offset data ; Get data area of packet.
mov ah,'D' ; Use "D" for discard. [20b]
mov [bx],ah ; And add it to the packet. [20b]
mov argbk1,1 ; Set data size to 1. [20b]
seof11: mov ah,'Z' ; EOF packet.
call spack ; Send the packet.
jmp abort
call rpack ; Get a packet.
jmp r ; Trashed packet don't change state, retry.
cmp ah,'Y' ; ACK?
jne seof2 ; If not try next.
mov ax,pktnum ; Get the packet number.
cmp ax,argblk ; Is it the right packet number?
jz seof12
ret ; If not hold out for the right one.
seof12: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pktnum,ax ; Save modulo 64 of the number.
inc numpkt ; Increment the number of packets.
mov ah,numtry ; Get the number of tries.
mov oldtry,ah ; Save it.
mov numtry,0 ; Reset the number of tries.
mov ah,closf ; Close the file.
mov dx,offset fcb
int dos
call gtnfil ; Get the next file.
jmp seof13 ; No more.
mov state,'F' ; Set the state to file send.
cmp cxzflg,'X' ; Control-X seen? [20b]
jne seof14
call cxmsg ; Clear out the interrupt msg. [20b]
seof14: mov cxzflg,0 ; Reset the flag. [20b]
ret
seof13: mov state,'B' ; Set the state to EOT.
ret
seof2: cmp ah,'N' ; NAK?
jne seof3 ; Try and see if its an error packet.
call rtpos ; Position cursor.
inc numrtr ; Increment the number of retries
mov ax,numrtr
call nout ; Write the number of retries.
mov ax,pktnum ; Get the present packet number.
inc ax ; Increment.
and ax,03FH ; Account for wraparound. [18]
cmp ax,argblk ; Is the packet's number one more than now?
jz seof12 ; Just as good as a ACK; go to the ACK code.
ret ; If not go try again.
seof3: cmp ah,'E' ; Is it an error packet?
jne seof4
call error
seof4: jmp abort
SEOF ENDP
; Send EOT
SEOT PROC NEAR
cmp numtry,maxtry ; Have we reached the maximum number of tries?
jl seot1
call erpos ; Position cursor.
mov dx,offset erms14
mov ah,prstr
int dos ; Print an error message.
jmp abort ; Change the state to abort.
seot1: inc numtry ; Increment it.
mov ax,pktnum ; Get the packet number.
mov argblk,ax
mov argbk1,0 ; No data.
mov ah,'B' ; EOF packet.
call spack ; Send the packet.
jmp abort
call rpack ; Get a packet.
jmp r ; Trashed packet don't change state, retry.
cmp ah,'Y' ; ACK?
jne seot2 ; If not try next.
mov ax,pktnum ; Get the packet number.
cmp ax,argblk ; Is it the right packet number?
jz seot12
ret ; If not hold out for the right one.
seot12: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pktnum,ax ; Save modulo 64 of the number.
inc numpkt ; Increment the number of packets.
mov ah,numtry ; Get the number of tries.
mov oldtry,ah ; Save it.
mov numtry,0 ; Reset the number of tries.
mov state,'C' ; Set the state to file send.
ret
seot2: cmp ah,'N' ; NAK?
jne seot3 ; Is it error.
call rtpos ; Position cursor.
inc numrtr ; Increment the number of retries
mov ax,numrtr
call nout ; Write the number of retries.
mov ax,pktnum ; Get the present packet number.
inc ax ; Increment.
and ax,03FH ; Account for wraparound. [18]
cmp ax,argblk ; Is the packet's number one more than now?
jz seot12 ; Just as good as a ACK; go to the ACK code.
ret ; If not go try again.
seot3: cmp ah,'E' ; Is it an error packet.
jne seot4
call error
seot4: jmp abort
SEOT ENDP
; Here is the bulk of the file I/O. Good luck.
; File routines
; Output the chars in a packet.
FILEIO PROC NEAR
ptchr: mov temp1,ax ; Save the size.
mov bx,offset data ; Beginning of received packet data.
mov outpnt,bx ; Remember where we are.
mov ch,rquote ; Quote char.
ptchr1: dec temp1 ; Decrement # of chars in packet.
jnl pt1
jmp rskp ; Return successfully if done.
pt1: dec chrcnt ; Decrement number of chars in dta.
jns ptchr2 ; Continue if space left.
call outbuf ; Output it if full.
jmp r ; Error return if disk is full.
ptchr2: mov bx,outpnt ; Get position in output buffer.
mov ah,[bx] ; Grab a char.
inc bx
mov outpnt,bx ; and bump pointer.
cmp ah,ch ; Is it the quote char?
jne ptchr4 ; If not proceed.
mov ah,[bx] ; Get the quoted character
inc bx
mov outpnt,bx ; and bump pointer.
dec temp1 ; Decrement # of chars in packet.
mov dh,ah ; Save the char.
and ah,80H ; Turn off all but the parity bit.
mov dl,ah ; Save the parity bit.
mov ah,dh ; Get the char.
and ah,7FH ; Turn off the parity bit.
cmp ah,ch ; Is it the quote char?
jz ptchr3 ; If so just go write it out.
mov ah,dh ; Get the char.
add ah,40H ; Make it a control char again.
and ah,7FH ; Modulo 128.
ptchr3: or ah,dl ; Or in the parity bit.
ptchr4: mov bx,bufpnt ; Destination buffer.
mov [bx],ah ; Store it.
inc bx
mov bufpnt,bx ; Update the pointer
jmp ptchr1 ; and loop to next char.
; output the buffer, reset bufpnt and chrcnt
outbuf: push bx
mov ah,writef ; The write code.
mov dx,offset fcb
int dos ; Write the record.
pop bx
cmp al,0 ; Successful.
jz outbf1
push ax ; Remember the return code. [20d]
call abfil ; Fix things up before aborting. [20d]
pop ax ; Retrive return code. [20d]
cmp al,01
jz outbf0
call erpos
mov ah,prstr
mov dx,offset erms17 ; Record length exceeds dta.
int dos
ret
outbf0: call erpos
mov ah,prstr ; Tell about it.
mov dx,offset erms11 ; Disk full error.
int dos
ret
outbf1: mov bx,offset buff ; Addr for beginning.
mov bufpnt,bx ; Store addr for beginning.
mov ax,bufsiz-1 ; Buffer size.
mov chrcnt,ax ; Number of chars left.
jmp rskp
; Tidy up before aborting. [20d]
ABFIL PROC NEAR
mov ah,closf ; Close the file.
mov dx,offset fcb
int dos
cmp abfflg,1 ; Delete what got across or keep it?
jne abfil0 ; Nope, keep it.
mov ah,delf ; Delete it.
mov dx,offset fcb
int dos
abfil0: mov bx,offset erms10 ; Text of message to send.
call errpack ; Send an error packet.
ret
ABFIL ENDP
; General routine for sending an error packet. Register BX should
; point to the text of the message being sent in the packet. [20f]
ERRPACK PROC NEAR
mov di,offset data ; Where to put the message.
mov al,0
errp1: mov ah,[bx]
cmp ah,'$' ; At end of message?
je errp2
inc al ; Remember number of chars in msg.
mov [di],ah
inc bx
inc di
jmp errp1
errp2: mov ah,0
mov argbk1,ax
mov ah,'E' ; And send an error packet.
call spack
ret ; Return if succeed or fail.
nop
nop
ret
ERRPACK ENDP
; Get the chars from the file.
gtchr: mov ch,squote ; Keep quote char in c.
mov ah,filflg ; Get the file flag.
cmp ah,0 ; Is there anything in the DMA?
jz gtchr0 ; Yup, proceed.
mov cl,0 ; No chars yet.
call inbuf
jmp gtceof ; No more chars, go return EOF.
gtchr0: mov al,spsiz ; Get the maximum packet size.
sub al,5 ; Subtract the overhead.
mov ah,0
mov temp1,ax ; Number of chars we're to get.
mov bx,offset filbuf ; Where to put the data.
mov cbfptr,bx ; Remember where we are.
mov cl,0 ; No chars.
gtchr1: dec temp1 ; Decrement the number of chars left.
jns gtchr2 ; Go on if there is more than one left.
mov al,cl ; Return the count in A.
mov ah,0
jmp rskp
gtchr2: mov ax,chrcnt
dec ax
jl gtchr3
mov chrcnt,ax
jmp gtchr4
gtchr3: call inbuf ; Get another buffer full.
jmp gtceof
cmp chrcnt,0
jne gtchr4
sub cl,2 ; Don't count controllified Z.
mov al,cl
mov ah,0
jmp rskp
gtchr4: mov bx,bufpnt ; Position in DMA.
mov ah,[bx] ; Get a char from the file.
inc bx
mov bufpnt,bx
mov dh,ah ; Save the char.
and ah,80H ; Turn off all but parity.
mov dl,ah ; Save the parity bit.
mov ah,dh ; Restore the char.
and ah,7FH ; Turn off the parity.
cmp ah,' ' ; Compare to a space.
jl gtchr5 ; If less then its a control char, handle it.
cmp ah,del ; Is the char a delete?
jz gtchr5 ; Go quote it.
cmp ah,ch ; Is it the quote char?
jne gtchr8 ; If not proceed.
dec temp1 ; Decrement the char total remaining.
mov bx,cbfptr ; Position in character buffer.
mov [bx],ah ; Put the char in the buffer.
inc bx
mov cbfptr,bx
inc cl ; Increment the char count.
jmp gtchr8
gtchr5: or ah,dl ; Turn on the parity bit.
cmp ah,('Z'-100O) ; Is it a ^Z?
jne gtchr7 ; If not just proceed.
mov ah,eoflag ; EOF flag set?
cmp ah,0
jz gtchr6 ; If not just go on.
mov bx,bufpnt
mov ax,chrcnt
mov dh,al ; Get number of chars left in DMA.
gtch51: dec dh
mov ah,dh
jns gtch52 ; Any chars left?
mov chrcnt,0 ; If not, say so.
mov al,cl ; Return the count in A.
mov ah,0
jmp rskp
gtch52: mov ah,[bx] ; Get the next char.
inc bx ; Move the pointer.
cmp ah,('Z'-100O) ; Is it a ^Z?
jz gtch51 ; If so see if they rest are.
gtchr6: mov ah,('Z'-100O) ; Restore the ^Z.
gtchr7: xchg ah,al
mov ah,0
mov temp2,ax ; Save the char.
dec temp1 ; Decrement char counter.
mov bx,cbfptr ; Position in character buffer.
mov [bx],ch ; Put the quote in the buffer.
inc bx
mov cbfptr,bx
inc cl ; Increment the char count.
mov ax,temp2 ; Get the control char back.
xchg al,ah
add ah,40H ; Make the non-control.
and ah,7fH ; Modulo 200 octal.
gtchr8: mov bx,cbfptr ; Position in character buffer.
or ah,dl ; Or in the parity bit.
mov [bx],ah ; Put the char in the buffer.
inc bx
mov cbfptr,bx
inc cl ; Increment the char count.
jmp gtchr1 ; Go around again.
gtceof: cmp cl,0 ; Had we gotten any data?
je gteof0 ; Nope.
mov al,cl
mov ah,0
jmp rskp
gteof0: mov ah,0FFH ; Get a minus one.
ret
inbuf: mov ah,eoflag ; Have we reached the end?
cmp ah,0
jz inbuf0
ret ; Return if set.
inbuf0: push bx
push cx
mov bx,offset buff ; Set the r/w buffer pointer.
mov bufpnt,bx
mov ah,readf ; Read a record.
mov dx,offset fcb
int dos
mov cx,filsiz
cmp cx,0 ; Check for 128 chars or less left.
jne inbuf1 ; Still have data left.
mov ax,ds
mov es,ax
mov si,offset filsiz+2
mov di,offset bufhex
cmps filsiz+2,es:bufhex
ja inbuf1 ; More than 128 chars.
mov eoflag,0FFH ; Set End-of-file.
mov cx,filsiz+2
mov chrcnt,cx ; Return proper number of chars.
mov filflg,0 ; Buffer not empty.
pop cx
pop bx
jmp rskp
inbuf1: sub filsiz+2,80H ; Sent another 128 chars.
sbb filsiz,0 ; Account for the doubleword.
mov al,80H ; Use as counter for number of chars read.
pop cx
pop bx
cmp filflg,0 ; Ever used DMS?
jnz inbf21 ; Nope, then don't change count.
dec al ; Fix boundary error.
inbf21: mov ah,0 ; Zero the flag (buffer not empty).
mov chrcnt,ax ; Number of chars read from file.
mov filflg,0 ; Buffer not empty.
jmp rskp
getfil: mov ah,0FFH
mov filflg,ah ; Nothing in the DMA.
mov ax,0
mov eoflag,ah ; Not the end of file.
mov bx,offset fcb+0CH
mov [bx],ax ; Zero the current block number.
mov bx,offset fcb+0EH
mov [bx],ax ; Ditto for Lrecl.
mov bx,offset fcb+20H
mov [bx],ah ; Zero the current record (of block).
inc bx
mov [bx],ax ; Same for record (of file).
mov bx,offset fcb+23H
mov [bx],ax
mov ah,openf ; Open the file.
mov dx,offset fcb
int dos
mov bx,offset fcb+18 ; File size in bytes (hi order word).
mov di,offset filsiz ; Where to put the info.
mov ax,[bx]
mov [di],ax
mov bx,offset fcb+16 ; Lo order word.
mov ax,[bx]
mov 2[di],ax
sub filsiz+2,1 ; Don't count the ^Z.
sbb filsiz,0
jmp rskp
gtnfil: cmp cxzflg,'Z' ; Did we have a ^Z? [20b]
je gtn5 ; If yes, we're done sending files. [20b]
cmp wldflg,0 ; Was there a "*"? [7 start]
je gtn5 ; Nope.
mov bx,offset cpfcb ; Get FCB from last check for file.
mov di,offset fcb ; Copy to FCB.
mov cl,37 ; Size of FCB.
call fcbcpy
gtn2: mov ah,snext
mov dx,offset fcb ; More files?
int dos
cmp al,0FFH
je gtn5
mov bx,offset fcb
mov di,offset cpfcb
mov cl,37
call fcbcpy ; Copy from FCB.
mov di,offset fcb+1 ; Get name of next file to send.
mov bx,offset buff+1
mov cl,11
call fcbcpy
call getfil ; Initialize
jmp r
jmp rskp
gtn5: mov wldflg,0 ; Reset wild card flag.
ret ; [7 end]
; Get the file name (including host to micro translation)
gofil: mov bx,offset data ; Get the address of the file name.
mov datptr,bx ; Store the address.
mov bx,offset fcb+1 ; Address of the FCB.
mov fcbptr,bx ; Save it.
mov ax,0
mov temp1,ax ; Initialize the char count.
mov temp2,ax
mov si,offset fcb
mov [si],ah ; Set the drive to default to current.
mov ch,' '
gofil1: mov [bx],ch ; Blank the FCB.
inc bx
inc ah
cmp ah,0BH ; Twelve?
jl gofil1
gofil2: mov bx,datptr ; Get the NAME field.
mov ah,[bx]
inc bx
mov datptr,bx
cmp ah,'.' ; Seperator?
jne gofil3
mov bx,offset fcb+9H
mov fcbptr,bx
mov ax,temp1
mov temp2,ax
mov temp1,9H
jmp gofil6
gofil3: cmp ah,0 ; Trailing null?
jz gofil7 ; Then we're done.
mov bx,fcbptr
mov [bx],ah
inc bx
mov fcbptr,bx
mov ax,temp1 ; Get the char count.
inc ax
mov temp1,ax
cmp ax,8H ; Are we finished with this field?
jl gofil2
gofil4: mov temp2,ax
mov bx,datptr
mov ah,[bx]
inc bx
mov datptr,bx
cmp ah,0
jz gofil7
cmp ah,'.' ; Is this the terminator?
jne gofil4 ; Go until we find it.
gofil6: mov bx,datptr ; Get the TYPE field.
mov ah,[bx]
inc bx
mov datptr,bx
cmp ah,0 ; Trailing null?
jz gofil7 ; Then we're done.
mov bx,fcbptr
mov [bx],ah
inc bx
mov fcbptr,bx
inc temp1 ; Increment char count.
cmp temp1,0CH ; Are we finished with this field?
jl gofil6
gofil7: mov bx,datptr
mov ah,'$'
mov [bx],ah ; Put in a dollar sign for printing.
call clrfln
mov ah,prstr ; Print the file name.
mov dx,offset data
int dos
mov ah,flwflg ; Is file warning on?
cmp ah,0
jnz gf7x
jmp gofil9 ; If not, just proceed.
gf7x: mov ah,openf ; See if the file exists.
mov dx,offset fcb
int dos
cmp al,0FFH ; Does it exist?
jnz gf8x
jmp gofil9 ; If not create it.
gf8x:
IF ibmpc
mov ah,2 ; Position cursor.
mov dx,scrfr
mov bh,0
int bios
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrfr ; and string to move cursor
int dos ; Print the string
ENDIF
mov ah,prstr ; Inform the user we are renaming the file.
mov dx,offset infms5
int dos
mov ax,temp2 ; Get the number of chars in the file name.
cmp ax,0
jne gofil8
mov ax,temp1
mov temp2,ax
gofil8: mov ch,0
mov cl,al
mov al,0 ; Says if first field is full.
cmp cl,9H ; Is the first field full?
jne gofl81
mov al,0FFH ; Set a flag saying so.
dec cl
gofl81: mov bx,offset fcb ; Get the FCB.
add bx,cx ; Add in the character number.
mov ah,'&'
mov [bx],ah ; Replace the char with an ampersand.
push ax
push bx
mov ah,openf ; See if the file exists.
mov dx,offset fcb
int dos
pop bx
cmp al,0FFH ; Does it exist?
pop ax
jz gofl89 ; If not create it.
cmp al,0 ; Get the flag.
jz gofl83
dec cl ; Decrement the number of chars.
cmp cl,0
jz gofl88 ; If no more, die.
jmp gofl81
gofl83: inc cl ; Increment the number of chars.
cmp cl,9H ; Are we to the end?
jl gofl81 ; If not try again ; else fail.
gofl88: call erpos ; Position cursor.
mov ah,prstr ; Tell the user that we can't rename it.
mov dx,offset ermes4
int dos
mov bx,dx ; Tell host can't rename. [20f]
call errpack ; Send error packet before abort. [20f]
ret
gofl89: mov bx,offset fcb+0CH ; Point past the end of the file name.
mov dh,[bx] ; Save the present contents.
mov ah,'$'
mov [bx],ah ; Put in a dollar sign.
push dx
mov ah,prstr ; Print the file name.
mov dx,offset fcb+1
int dos
pop dx
mov bx,offset fcb+0CH ; Restore over the dollar sign.
mov [bx],dh
gofil9: mov ah,delf ; Delete the file if it exists.
mov dx,offset fcb
int dos
mov ax,0
mov si,offset fcb+0CH
mov [si],ax ; Zero current block.
mov si,offset fcb+0EH
mov [si],ax ; Same for Lrecl.
mov si,offset fcb+20H
mov [si],ah ; Zero the current record (within block).
inc si
mov [si],ax ; Zero record (within file).
mov si,offset fcb+23H
mov [si],ax
mov ah,makef ; Now create it.
mov dx,offset fcb
int dos
cmp al,0FFH ; Is the disk full?
je gf9x
jmp rskp
gf9x: call erpos ; Position cursor.
mov ah,prstr ; If so tell the user.
mov dx,offset erms11
int dos
ret
FILEIO ENDP
; Packet routines
; Send_Packet
; This routine assembles a packet from the arguments given and sends it
; to the host.
;
; Expects the following:
; AH - Type of packet (D,Y,N,S,R,E,F,Z,T)
; ARGBLK - Packet sequence number
; ARGBK1 - Number of data characters
; Returns: +1 always
SPKT PROC NEAR
spack: push ax ; Save the packet type.
IF ibmpc
call clrbuf ; Clear the input buffer. [20e]
ENDIF
mov bx,offset packet ; Get address of the send packet.
mov ah,soh ; Get the start of header char.
mov [bx],ah ; Put in the packet.
inc bx ; Point to next char.
mov ax,argbk1 ; Get the number of data chars.
xchg ah,al
add ah,' '+3 ; Real packet character count made printable.
mov [bx],ah ; Put in the packet.
inc bx ; Point to next char.
mov cl,ah ; Start the checksum.
mov ax,argblk ; Get the packet number.
xchg ah,al
add ah,' ' ; Add a space so the number is printable.
mov [bx],ah ; Put in the packet.
inc bx ; Point to next char.
add cl,ah ; Add the packet number to the checksum.
pop ax ; Get the packet type.
mov [bx],ah ; Put in the packet.
inc bx ; Point to next char.
add cl,ah ; Add the type to the checksum.
mov dx,argbk1 ; Get the packet size.
spack2: cmp dx,0 ; Are there any chars of data?
jz spack3 ; No, finish up.
dec dx ; Decrement the char count.
mov ah,[bx] ; Get the next char.
inc bx ; Point to next char.
add cl,ah ; Add the char to the checksum.
cmp ah,0
jns spack2
mov hierr,0FFH ; set err flag.
jmp spack2 ; Go try again.
spack3: cmp hierr,0
je sp3x ; Nothing special to do.
call biterr
mov hierr,0 ; Reset.
sp3x: mov ah,cl ; Get the character total.
mov ch,cl ; Save here too (need 'cl' for shift).
and ah,0C0H ; Turn off all but the two high order bits.
mov cl,6
shr ah,cl ; Shift them into the low order position.
mov cl,ch
add ah,cl ; Add it to the old bits.
and ah,3FH ; Turn off the two high order bits. (MOD 64)
add ah,' ' ; Add a space so the number is printable.
mov [bx],ah ; Put in the packet.
inc bx ; Point to next char.
mov ah,seol ; Get the EOL the other host wants.
mov [bx],ah ; Put in the packet.
inc bx ; Point to next char.
mov ah,0 ; Get a null.
mov [bx],ah ; Put in the packet.
cmp debug,0 ; debug mode.
je spack4
inc bx
mov ah,'$'
mov [bx],ah
IF ibmpc
mov ah,2
mov dx,scrsp
mov bh,0
int bios
ENDIF
IF Z100
mov ah,prstr ; Get print string function
mov dx,offset scrsp ; and string to move cursor
int dos ; Print the string
ENDIF
mov ah,prstr
mov dx,offset spmes
int dos
mov dx,offset packet
mov ah,prstr
int dos ; debug end.
spack4: call outpkt ; Call the system dependent routine.
jmp r
jmp rskp
SPKT ENDP
; Write out a packet.
OUTPKT PROC NEAR
mov dh,spad ; Get the number of padding chars.
outpk2: dec dh
cmp dh,0
jl outpk3 ; If none left proceed.
mov ah,spadch ; Get the padding char.
call outchr ; Output it.
jmp outpk2
outpk3: mov bx,offset packet ; Point to the packet.
outlup: mov ah,[bx] ; Get the next character.
cmp ah,0 ; Is it a null?
jnz outlp2
jmp rskp
outlp2: call outchr ; Output the character.
jmp r
inc bx ; Increment the char pointer.
jmp outlup
OUTPKT ENDP
;************************System Dependent****************************
; Put a char in AH to the port.
PORT PROC NEAR
IF ibmpc
outchr: sub cx,cx ; [14 start]
mov al,ah ; Parity routine works on AL. [16]
call dopar ; Set parity appropriately. [10]
mov ah,al ; Don't overwrite character with status. [16]
mov dx,mdstat ; Get port status. [19b]
outch1: in al,dx
test al,20H ; Transmitter ready?
jnz outch2 ; Yes
loop outch1
jmp r ; Timeout
outch2: mov al,ah ; Now send it out
mov dx,mddat ; [19b]
out dx,al
jmp rskp ; [14 end]
ENDIF
IF Z100
outchr: mov al,ah ; Yes, get the character into al
mov cx,0
call dopar ; Set parity appropriately. [10]
outch1: call bios_auxout ; Send the character
jmp rskp
ENDIF
;************************System Dependent****************************
;
; Get a char from the port and return in AH.
inchr:
IF ibmpc
call prtchr ; Get character if ready. [14]
jmp inchr3 ; Got it in AL. [14]
ENDIF
IF Z100
push bx ; Save BX
mov ah,chr_status ; Get the function
mov al,chr_sfgs ; And the subfunction
call bios_auxfunc ; Determine if anything to input
cmp bl,0 ; Is there?
jnz inchr3 ; Yes, go get it
pop bx ; And restore BX
ENDIF
mov ah,constat ; Is a char on the console?
int dos
cmp al,0
jz inchr ; If not go look for another char.
mov ah,conin ; Get the char.
int dos
mov ah,al
cmp ah,cr ; Is it a carriage return?
je inchr4 ; If yes, then leave.
cmp ah,'Z'-100O ; Control-Z? [20b]
je inchr2 ; Yes - flag it. [20b]
cmp ah,'X'-100O ; Control-X? [20b]
je inchr2 ; Yes - flag it. [20b]
jmp inchr ; Wait for some kind of input.
inchr2: add ah,100O ; Make it printable. [20b]
mov cxzflg,ah ; Remember what we saw. [20b]
jmp inchr ; Continue getting input. [20b]
inchr4: ret
inchr3:
IF Z100
mov ah,chr_read ; Get the function to read
call bios_auxfunc ; Get a character
pop bx ; Restore BX
ENDIF
mov ah,al
cmp parflg,parnon ; Is the parity none? [10]
je inchr5 ; We're done. [10]
and ah,7FH ; Turn off the parity bit.
inchr5: jmp rskp
; Set parity for character in Register AL.
dopar: cmp parflg,parnon ; No parity? [10 start]
je parret ; Just return
cmp parflg,parevn ; Even parity?
jne dopar0
and al,07FH ; Strip parity.
jpe parret ; Already even, leave it.
or al,080H ; Make it even parity.
jmp parret
dopar0: cmp parflg,parmrk ; Mark parity?
jne dopar1
or al,080H ; Turn on the parity bit.
jmp parret
dopar1: cmp parflg,parodd ; Odd parity?
jne dopar2
and al,07FH ; Strip parity.
jpo parret ; Already odd, leave it.
or al,080H ; Make it odd parity.
jmp parret
dopar2: and al,07FH ; Space parity - turn off parity bit.
parret: ret ; [10 end]
PORT ENDP
; Clear the input buffer before sending a packet. [20e]
IF ibmpc
CLRBUF PROC NEAR
lea ax,cs:source ; Initialize the pointers
mov cs:srcpnt,ax
mov cs:savesi,ax
mov cs:count,0
mov di,cs:srcpnt ; Where to store bytes
mov ax,cs ; Ready ES for string operations
mov es,ax
mov si,0 ; Where to fetch bytes
ret
CLRBUF ENDP
ENDIF
; Receive_Packet
; This routine waits for a packet arrive from the host. It reads
; chars until it finds a SOH.
RPACK PROC NEAR
IF ibmpc
mov ah,2
mov dx,scrst ; Position cursor.
mov bh,0
int bios
ENDIF
IF Z100
mov ah,prstr ; Get the function to print string
mov dx,offset scrst ; Get the string address
int dos ; Position the cursor
ENDIF
mov ah,prstr
mov dx,offset infms0
int dos
rpack5: call inpkt ; Read up to a carriage return.
jmp r ; Return bad.
rpack0: call getchr ; Get a character.
jmp r ; Hit the carriage return, return bad.
cmp ah,soh ; Is the char the start of header char?
jne rpack0 ; No, go until it is.
rpack1: call getchr ; Get a character.
jmp r ; Hit the carriage return, return bad.
cmp ah,soh ; Is the char the start of header char?
jz rpack1 ; Yes, then go start over.
mov cl,ah ; Start the checksum.
sub ah,' '+3 ; Get the real data count.
mov dh,ah ; Save it for later.
mov al,ah ; Swap halves.
mov ah,0
mov argbk1,ax ; Save the data count.
call getchr ; Get a character.
jmp r ; Hit the carriage return, return bad.
cmp ah,soh ; Is the char the start of header char?
jz rpack1 ; Yes, then go start over.
add cl,ah ; Add it to the checksum.
sub ah,' ' ; Get the real packet number.
mov al,ah ; Swap halves.
mov ah,0
mov argblk,ax ; Save the packet number.
call getchr ; Get a character.
jmp r ; Hit the carriage return, return bad.
cmp ah,soh ; Is the char the start of header char?
jz rpack1 ; Yes, then go start over.
mov temp,ax ; Save the message type. [11]
add cl,ah ; Add it to the checksum.
mov bx,offset data ; Point to the data buffer.
rpack2: dec dh ; Any data characters?
js rpack3 ; If not go get the checksum.
call getchr ; Get a character.
jmp r ; Hit the carriage return, return bad.
cmp ah,soh ; Is the char the start of header char?
jz rpack1 ; Yes, then go start over.
mov [bx],ah ; Put the char into the packet.
inc bx ; Point to the next character.
add cl,ah ; Add it to the checksum.
jmp rpack2 ; Go get another.
rpack3: call getchr ; Get a character.
jmp r ; Hit the carriage return, return bad.
cmp ah,soh ; Is the char the start of header char?
jz rpack1 ; Yes, then go start over.
sub ah,' ' ; Turn the char back into a number.
mov dh,cl ; Get the character total.
and dh,0C0H ; Turn off all but the two high order bits.
mov ch,cl
mov cl,6
shr dh,cl ; Shift them into the low order position.
mov cl,ch
add dh,cl ; Add it to the old bits.
and dh,3FH ; Turn off the two high order bits. (MOD 64)
cmp dh,ah ; Are they equal?
jz rpack4 ; If so finish up.
ret
rpack4: mov ah,0
mov [bx],ah ; Put a null at the end of the data.
mov ax,temp ; Get the type. [11]
jmp rskp
RPACK ENDP
INPKT PROC NEAR
mov bl,cxzflg ; Remember original value. [20b]
mov tmp,bl ; Store it here. [20b]
mov bx,offset recpkt ; Point to the beginning of the packet.
mov incnt,0
inpkt2: call inchr ; Get a character.
jmp inpkt0 ; Return failure. [20b]
nop ; Make it three bytes long. [20b]
mov [bx],ah ; Put the char in the packet.
inc bx
inc incnt
cmp ah,reol ; Is it the EOL char?
jne inpkt2 ; If not loop for another.
cmp incnt,1 ; Ignore bare CR. [2 start]
jne inpkt6
mov incnt,0
mov bx,offset recpkt
jmp inpkt2 ; [2 end]
inpkt6: cmp ibmflg,0 ; Is this the (dumb) IBM mainframe?
jz inpkt4 ; If not then proceed.
inpkt5: cmp state,'S' ; Check if this is the Send-Init packet.
jz inpkt4 ; If so don't wait for the XON.
inpkt3: call inchr ; Wait for the turn around char.
jmp inpkt0 ; Return failure. [20b]
nop ; Make it three bytes long. [20b]
cmp ah,xon ; Is it the IBM turn around character?
jne inpkt3 ; If not, go until it is.
inpkt4: mov bx,offset recpkt
mov pktptr,bx ; Save the packet pointer.
mov bl,tmp ; Get the original value. [20b]
cmp bl,cxzflg ; Did ^X/^Z flag change? [20b]
je inpkx ; If not, just return. [20b]
call intmsg ; Else, say we saw the interrupt. [20b]
inpkx: jmp rskp ; If so we are done.
inpkt0: mov bl,tmp ; Get the original value. [20b]
cmp bl,cxzflg ; Did ^X/^Z flag change? [20b]
je inpky ; If not, just return failure. [20b]
call intmsg ; Else, say we saw the interrupt. [20b]
inpky: jmp r
INPKT ENDP
GETCHR PROC NEAR
push bx
mov bx,pktptr ; Get the packet pointer.
mov ah,[bx] ; Get the char.
inc bx
mov pktptr,bx
pop bx ; Restore BX.
cmp ah,reol ; Is it the EOL char?
jne getcr2 ; If not return retskp.
ret ; If so return failure.
getcr2: jmp rskp
GETCHR ENDP
; This is where we go if we get an error packet. A call to ERROR
; positions the cursor and prints the message. A call to ERROR1
; just prints a CRLF and then the message. [8]
ERROR PROC NEAR
mov state,'A' ; Set the state to abort.
call erpos ; Position the cursor.
jmp error2
error1: mov ah,prstr
mov dx,offset crlf
int dos
error2: mov bx,argbk1 ; Get the length of the data.
add bx,offset data ; Get to the end of the string.
mov ah,'$' ; Put a dollar sign at the end.
mov [bx],ah
mov ah,prstr ; Print the error message.
mov dx,offset data
int dos
ret
ERROR ENDP
; LOGOUT - tell remote KERSRV to logout.
LOGOUT PROC NEAR ; [8 start]
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r
call logo
jmp rskp ; Go get another command whether we ....
jmp rskp ; .... succeed or fail.
LOGOUT ENDP
LOGO PROC NEAR
mov numtry,0 ; Initialize count.
call serini ; Initialize port. [14]
logo1: mov ah,numtry
cmp ah,maxtry ; Too many times?
js logo3 ; No, try it.
logo2: mov ah,prstr
mov dx,offset erms19
int dos
call serrst ; Reset port. [14]
ret
logo3: inc numtry ; Increment number of tries.
mov argblk,0 ; Packet number zero.
mov argbk1,1 ; One piece of data.
mov bx,offset data
mov ah,'L'
mov [bx],ah ; Logout the remote host.
mov ah,'G' ; Generic command packet.
call spack
jmp logo2 ; Tell user and die.
nop
call rpack5 ; Get ACK (w/o screen msgs.)
jmp logo1 ; Go try again.
nop
cmp ah,'Y' ; ACK?
jne logo4
call serrst ; Reset port. [14]
jmp rskp
logo4: cmp ah,'E' ; Error packet?
jnz logo1 ; Try sending the packet again.
call error1
call serrst ; Reset port. [14]
ret
LOGO ENDP
; FINISH - tell remote KERSRV to exit.
FINISH PROC NEAR
mov ah,cmcfm ; Parse a confirm.
call comnd
jmp r
mov numtry,0 ; Initialize count.
call serini ; Initialize port. [14]
fin1: mov ah,numtry
cmp ah,maxtry ; Too many times?
js fin3 ; Nope, try it.
fin2: mov ah,prstr
mov dx,offset erms18
int dos
call serrst ; Reset port. [14]
jmp rskp ; Go home.
fin3: inc numtry ; Increment number of tries.
mov argblk,0 ; Packet number zero.
mov argbk1,1 ; One piece of data.
mov bx,offset data
mov ah,'F'
mov [bx],ah ; Finish running Kermit.
mov ah,'G' ; Generic command packet.
call spack
jmp fin2 ; Tell user and die.
nop
call rpack5 ; Get ACK (w/o screen stuff).
jmp fin1 ; Go try again.
nop
cmp ah,'Y' ; Got an ACK?
jnz fin4
call serrst ; Reset port. [14]
jmp rskp ; Yes, then we're done.
fin4: cmp ah,'E' ; Error packet?
jnz fin1 ; Try sending it again.
call error1
call serrst ; Reset port. [14]
jmp rskp
FINISH ENDP
; BYE command - tell remote KERSRV to logout & exits to DOS.
BYE PROC NEAR
mov ah,cmcfm ; Parse a confirm.
call comnd
jmp r
call logo ; Tell the mainframe to logout.
jmp rskp ; Failed - don't exit.
mov extflg,1 ; Set exit flag.
jmp rskp ; [8 end]
BYE ENDP
; This is the 'exit' command. It leaves KERMIT and returns to DOS.
EXIT PROC NEAR
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r
mov extflg,1 ; Set the exit flag.
jmp rskp ; Then return to system.
EXIT ENDP
; This is the 'help' command. It gives a list of the commands.
HELP PROC NEAR
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r
mov ah,prstr ; Print a string to the console.
mov dx,offset tophlp ; The address of the help message.
int dos
jmp rskp
HELP ENDP
IF ibmpc
source db 2048 DUP(?) ; Buffer for data from port.
srcpnt dw 0 ; Pointer in buffer (DI).
count dw 0 ; Number of chars in int buffer.
savesi dw 0 ; Save SI register here.
telflg db 0 ; Are we acting as a terminal. [16] [17c]
mst dw 0 ; Modem status address. [19b]
mdat dw 0 ; Modem data address. [19b]
mdeoi db 0 ; End-of-Interrupt value. [19b]
ENDIF
; This is the CONNECT command.
TELNET PROC NEAR
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
mov ah,prstr ; Output
mov dx,offset crlf ; a crlf.
int dos
call dobaud ; Set baud rate. [19a]
call domsg ; Reassure user. [19b]
IF ibmpc
mov ah,3 ; Get cursor position. [17b start, 20g]
mov bh,0
int bios
cmp dh,24 ; Are we on row 25? [19d]
jne nobump ; Nope, then leave where it is. [19d]
dec dh ; Decrement ROW attribute. (DT)
mov ah,2
int bios ; [17b end]
nobump: mov cs:telflg,0FFH ; Turn on Telnet flag. [16] [17c] [20g]
call serini ; Initialize serial port. [14]
xor ax,ax
mov cx,ds ; Save DS in CX.
mov ds,ax ; Use low core.
mov bx,6CH ; "break" interrupt vector.
push [bx]
mov bx,6EH
push [bx]
mov bx,6CH
mov ax,offset intret
mov es,ax
mov [bx],es ; ignore break int's (pt to "iret").
mov bx,6EH
mov [bx],cs
mov ds,cx
mov ssp,sp ; Save SP to make an easy return.
ENDIF
IF Z100
mov ssp,sp ; Save current stack pointer.
ENDIF
telnoe: call plup ; Char at port (type to console) ?
IF ibmpc
cmp al,ESC
jne telx
jmp telesc
ENDIF
telx: cmp al,DEL ; Don't bother with deletes.
je telnoe
cmp al,XOFF ; Skip all the following too.
je telnoe
cmp al,XON
je telnoe
cmp al,00H ; Null.
je telnoe
IF ibmpc
cmp al,BELL
jne nobell
call beep
jmp telnoe
nobell: cmp al,TAB ; Tab ? [15]
jne notab ; No, skip the jump [15]
call dotab ; Yes, handle the tab [15]
jmp telnoe ; And get the next character [15]
notab: call dotty ; Use our own TTY I/O. [17b]
jmp telnoe
ENDIF
IF Z100
mov dl,al ; Get the character
mov ah,dconio ; and the function
int dos ; type the character
jmp telnoe ; Get next character
ENDIF
TELNET ENDP
; Reassure user about connection to the host. Tell him what escape
; sequence to use to return and the communications port and baud
; rate being used. [19b]
DOMSG PROC NEAR
mov ah,prstr
mov dx,offset tmsg1
int dos
call escprt
mov ah,prstr
mov dx,offset tmsg3
int dos
call baudprt ; Say what baud rate we're using. [19a]
IF ibmpc
mov ah,prstr
mov dx,offset tmsg4
int dos
mov tmp,'1' ; Assume COM1.
cmp comflg,1
je domsg0
mov tmp,'2' ; Nope, we're using COM2.
domsg0: mov dx,offset tmp
int dos
ENDIF
mov ah,prstr
mov tmp,']'
mov dx,offset tmp
int dos
mov dx,offset crlf ; Output 3 CRLF's.
int dos
int dos
int dos
ret
DOMSG ENDP
; Put character in AL to the screen. [17b start]
IF ibmpc
DOTTY PROC NEAR
push ax
mov ah,3 ;Get cursor
mov bh,0
int bios
pop ax
cmp al,8 ;Backspace?
je dotty3
cmp al,0DH ;CR?
je dotty4
cmp al,0AH ;LF?
je dotty5
cmp incmod,0 ;I/C?
jne dotty7
mov ah,9 ;Ordinary character
mov bx,curatt
mov cx,1
int bios
mov ah,2
mov bh,0
inc dl ;Step cursor
cmp dl,80 ;Overflow?
jne dotty2
ret
dotty1: inc dh
dotty6: mov ah,2
dotty2: int bios
ret
dotty3: dec dl ;BS
jge dotty6
ret
dotty4: mov dl,0 ;CR
jmp dotty6
dotty5: cmp dh,23 ;LF
jl dotty1
mov ah,8 ;Get attribute of last line
int bios
mov bh,ah
mov ax,0601H ;Scroll
sub cx,cx
mov dx,174FH
jmp dotty2
dotty7: mov temp,ax ;DK6 Save the character
mov temp1,dx ;Save the cursor
mov dl,78 ;Start shift at end of line
mov temp2,dx
mov ah,1 ;Turn off cursor
mov ch,20H
int bios
dotty8: mov ah,2 ;Position to col M
mov bh,0
mov dx,temp2
int bios
mov ah,8 ;Read char/attr
int bios
mov cx,ax ;Save it
mov ah,2 ;Position to col M+1
inc dx
int bios
mov ah,9 ;Write char/attr
mov al,cl
mov bl,ch
mov cx,1
int bios
dec dx
dec temp2
cmp dx,temp1
jne dotty8
mov ah,2 ;Position
mov bh,0
int bios
mov ax,temp ;Write the char
mov ah,9
mov bx,curatt ;In the current video mode
mov cx,1
int bios
mov ah,2 ;Step to next column
inc dl
int bios
mov ah,1 ;Turn on cursor
mov cx,0B0CH
int bios
ret ; [17b end]
DOTTY ENDP
ENDIF
EXTLN PROC NEAR
IF ibmpc
call serrst ; Reset serial port. [14]
mov sp,ssp
xor bx,bx
mov cx,ds ; Save DS register.
mov ds,bx ; Address low memory.
mov bx,6EH
pop [bx]
mov bx,6CH
pop [bx]
; mov bx,mdmintv+2 ; Restore old interrupt vectors.
; pop [bx]
; mov bx,mdmintv
; pop [bx]
mov ds,cx ; Restore DS.
xor bx,bx
mov cs:telflg,0 ; Not acting as terminal anymore. [16] [17c] [20g]
; sti
ENDIF
IF Z100
mov sp,ssp
ENDIF
mov ah,prstr
mov dx,offset tmsg2
int dos
jmp rskp
EXTLN ENDP
;[14 start] Common initialization for using serial port.
SERINI PROC NEAR
IF ibmpc
cli ; Disable interrupts
cld ; Do increments in string operations
xor ax,ax ; Address low memory
mov es,ax
mov bx,mdintv ; Save serial card interrupt vector. [19b]
mov ax,es:[bx]
mov savsci,ax
mov ax,offset serint ; And point it to my routine
mov es:[bx],ax
add bx,2 ; Save CS register too. [19b]
mov ax,es:[bx]
mov savscs,ax
mov es:[bx],cs
call clrbuf ; Clear input buffer. [20e]
mov ax,mdstat ; [19b]
mov cs:mst,ax ; Use this address for status. [19b]
mov ax,mddat ; [19b]
mov cs:mdat,ax ; Use this address for data. [19b]
mov al,mdmeoi ; [19b]
mov cs:mdeoi,al ; Use to signify end-of-interrupt. [19b]
in al,21H ; Set up 8259 interrupt controller
and al,mden ; Enable INT3 or INT4. [19b]
out 21H,al
mov dx,mdcom ; Set up the serial card. [19b]
mov al,3
out dx,al
mov dl,0F9H ; [19b]
mov al,1 ; Set up interrupt enable register
out dx,al
mov dl,0FCH ; Enable interrupts from serial card
mov al,0BH
out dx,al
sti ; Allow interrupts
mov dl,0F8H
in al,dx
ENDIF
ret
SERINI ENDP
SERRST PROC NEAR
IF ibmpc
cli ; Disable interrupts
mov dx,03FCH ; Disable modem interrupts
cmp comflg,1 ; Using port 1 ? [19b]
je srst0 ; Yes - continue. [19b]
mov dh,02 ; Set for port 2. [19b]
srst0: mov al,3 ; [new label - 19b]
out dx,al
in al,21H ; Interrupt controller
or al,mddis ; Inhibit IRQ3 or IRQ4. [19b]
out 21H,al
xor bx,bx ; Address low memory
mov es,bx
mov bx,mdintv ; Restore the serial card int vector [19b]
mov ax,savsci
mov es:[bx],ax
add bx,2 ; Restore CS too. [19b]
mov ax,savscs
mov es:[bx],ax
sti
ENDIF
ret
SERRST ENDP ; [14 end]
; *********** serial port interrupt routine ********
IF ibmpc
SERINT PROC NEAR
push dx
push ax
push es
push di
cld
mov di,cs:srcpnt ; Registers for storing data.
mov ax,cs
mov es,ax
mov dx,cs:mst ; Asynch status port. [19b]
in al,dx
test al,mdminp ; Data available?
jz retint ; Nope.
mov dx,cs:mdat ; [19b]
in al,dx
mov ah,0FFH ; Assume X-fer mode. [16 start]
cmp cs:telflg,0 ; File transfer or terminal mode? [17c]
jz srint0
mov ah,7FH ; Terminal mode (7 bits only).
srint0: and al,ah ; Fiddle with input. [16 end]
jz retint ; Ignore nulls.
cmp al,7FH ; Ignore rubouts, too.
jz retint
stosb ; Store char in buffer.
lea ax,cs:source
sub di,ax
and di,7FFH ; Truncate buffer here.
add di,ax
inc cs:count
retint: mov cs:srcpnt,di
sti
mov al,mdeoi ; [19b]
out intcon1,al ; Send End-of-Interrupt to 8259.
pop di
pop es
pop ax
pop dx
intret: iret
SERINT ENDP
ENDIF
PLUP PROC NEAR
call conchr ; Check keyboard. [15 begin]
jmp extln ; Exit from Telnet
nop ; In case it is a short jump (Z100)
call prtchr ; Check serial port
ret ; Got a character
nop ; Use up three bytes. [15 end]
nop
jmp plup
PLUP ENDP
;************************System Dependent****************************
; These I/O routines are similar to those just above.
PRTCHR PROC NEAR
IF ibmpc
cmp cs:count,0
jnz prtch2
jmp rskp ; No data - check console.
prtch2: cli ; Disable int's.
mov cx,ds
mov ax,cs
mov ds,ax
mov si,cs:savesi
lodsb ; Get char from buffer.
lea dx,cs:source
sub si,dx
and si,7FFH ; Truncate buffer after here.
add si,dx
dec cs:count
mov cs:savesi,si
mov ds,cx
sti ; Renable int's.
ret
ENDIF
IF Z100
push bx ; Save BX
mov ah,chr_status ; Get the function we want
mov al,chr_sfgs ; Get the subfunction to get status
call bios_auxfunc ; Perform the function
cmp bl,0 ; Anything in queue?
jne prtch1 ; Yes, go get it
pop bx ; Restore BX
jmp rskp ; No, give skip return
prtch1: mov ah,chr_read ; Want to read character
call bios_auxfunc ; Do it
and al,07FH ; Strip off parity bit
pop bx ; And restore BX
ret
ENDIF
PRTCHR ENDP
; Generate a short beep.
IF ibmpc
BEEP PROC NEAR
mov al,10110110B ; Gen a short beep (long one losses data.)
out timer+3,al ; Code snarfed from Technical Reference.
mov ax,533H
out timer+2,al
mov al,ah
out timer+2,al
in al,port_b
mov ah,al
or al,03
out port_b,al
sub cx,cx
mov bl,1
beep0: loop beep0
dec bl
jnz beep0
mov al,ah
out port_b,al
ret
BEEP ENDP
ENDIF
CONCHR PROC NEAR
IF ibmpc
mov ah,1 ; Get keyboard status.
int keyb
jnz cnc0x
jmp rskp
cnc0x: mov ah,0 ; Read a char.
int keyb
cmp al,0 ; Special char (cntrl-break)?
jnz nobrk ; Nope.
cmp ah,3 ; 3 in ah means nul code.
jz nobrk ; Pass nulls. [14]
cmp ah,83 ; Del Key? [14]
je cnc1r ; Yes - send a rubout. [14]
cmp ah,0 ; Cntrl-Break?
jne cnc1y
call sendbr ; Send a break. [20g]
cnc1y: jmp rskp
ENDIF
IF Z100
mov ah,dconio ; Determine if character present
mov dl,0ffH ; Want input
int dos ; Get status
cmp al,00H ; Any characters there?
jne nobrk ; if not, forget it
jmp rskp ; Give skip return
ENDIF
cnc1r: cmp delflg,0 ; Translate BS to DEL? [19c]
je dobs ; Nope, BS=BS [19c]
mov al,BS ; BS (will be converted to DEL) [15]
jmp nobrk
dobs: mov al,07FH ; ASCII rubout. [14]
nobrk: mov dl,al ; Store char here.
mov ah,escchr ; Get the escape char.
cmp ah,dl ; Is it an escape char?
jz intchr ; If so go process it.
cmp delflg,0 ; Translate BS to DEL? [19c]
je dobs1 ; Nope, BS=BS [19c]
cmp dl,BS ; Is it a backspace ? [15 begin]
jnz cch0 ; No, check for delete
mov dl,DEL ; Yes, get a delete
jmp cch1 ; And send that instead
cch0: cmp dl,DEL ; Is it a delete ?
jnz cch1 ; No, done checking then
mov dl,BS ; Yes, use a backspace
cch1: mov ax,dx ; Copy character back to AX [15 end]
dobs1: call dopar ; Set parity (if any). [10]
mov dx,ax
push dx
call prtout ; Output the char to the port.
pop dx
mov ah,ecoflg ; Get the echo flag.
cmp ah,0 ; Is it turned on?
jnz cnc1x
jmp rskp ; If not we're done here.
cnc1x: and dl,7FH
cmp dl,BS ; Backspace?
je cnc2x
cmp dl,CR ; Carriage return?
je cnc2x
IF ibmpc
cmp dl,BELL
jne cnc2y
call beep
jmp rskp
ENDIF
cnc2y: cmp dl,20H ; Is it a control char?
jge cnc2x
jmp rskp
cnc2x: mov ah,dconio ; Direct console output.
int dos ; Echo the char.
jmp rskp
CONCHR ENDP
; One routine to send a break for the IBM-PC and Z100. [20g]
SENDBR PROC NEAR
push cx
push dx
push ax
xor cx,cx ; Clear loop counter.
mov dx,mdcom ; Port address. [19b]
in al,dx ; Get current setting.
or al,BRKBIT ; Set send-break bit(s).
out dx,al ; Start the break.
pause: loop pause ; Wait a while.
xor al,BRKBIT ; Clear send-break bit(s).
out dx,al ; Stop the break.
pop ax
pop dx
pop cx
ret ; And return.
SENDBR ENDP
CONN PROC NEAR
intchr: mov ah,dconio ; Direct console I/O.
mov dl,0FFH ; Input.
int dos ; Get a char.
mov ah,al
cmp ah,0 ; Is the char a null?
jz intchr ; If so, go until we get a char.
mov bh,ah ; Save the actual char.
and ah,137O ; Convert to upper case.
cmp ah,'C' ; Is it close?
jne intch0
ret
intch0: cmp ah,'S' ; Is it status?
jnz inc0x
jmp stat01 ; If so, jump to stat01 (it will return).
inc0x: cmp ah,'B' ; Send a break? [20g]
jne inc1x ; No. [20g]
call sendbr ; Yes, so send a break. [20g]
jmp rskp ; And return. [20g]
inc1x: mov ah,bh ; Get the char.
cmp ah,'?' ; Is it help?
jne intch1 ; If not, go to the next check.
mov dx,offset inthlp ; If so, get the address of the help message.
mov ah,prstr ; Print it.
int dos
jmp intchr ; Get another char.
intch1: mov ch,ah ; Put the char into another reg.
mov ah,escchr ; Get the escape char.
cmp ah,ch ; Is it the escape char?
jne intch2 ; If not, go send a beep to the user.
mov al,ch
call dopar ; Set parity. [10]
intc11: mov dl,al
call prtout ; Output it.
jmp rskp ; Return, we are done here.
intch2: mov dl,'G'-100O ; Otherwise send a beep.
mov ah,dconio
int dos
jmp rskp
; Another similar I/O routine.
;************************System Dependent****************************
prtout: mov al,dl ; Char must be in al.
IF ibmpc
mov dx,mddat ; [19b]
out dx,al
ENDIF
IF Z100
call bios_auxout ; Send the character
ENDIF
ret
CONN ENDP
; [15 begin]
IF ibmpc ; Only for IBM-PC's. [20g]
DOTAB PROC NEAR
mov ah,3 ; Read current cursor position.
mov bh,0 ; This screen
int bios ; From bios
cmp dl,72 ; Are we at the last tab stop ?
jl dotab0 ; No, move to the next
cmp dl,79 ; Are we at the end ?
je dotab2 ; Yes, just return
add dl,1 ; No, move forward one position
jmp dotab1 ; Set the cursor position
dotab0: mov al,dl ; Get the column into al
push dx ; Save the current cursor position
xor ah,ah ; Zero the high end of ax
mov bl,8 ; Get an eight
xor bh,bh ; Zero high byte
div bl ; Divide by 8
mov al,ah ; Put the remainder in the low end
xor ah,ah ; Zero the high end
mov cl,8 ; Get an 8 into cl
xor ch,ch ; Zero high byte
sub cl,al ; Subtract al from cl
xor ch,ch ; Zero high end
pop dx ; Restore the current cursor position
add dl,cl ; And subtract column mod 8
dotab1: mov ah,2 ; Set cursor position
mov bh,0 ; This screen
int bios ; Bios call
dotab2: ret ; Return
DOTAB ENDP
ENDIF ; [20g]
; [15 end]
IF ibmpc ; [20g]
TELESC PROC NEAR
cmp vtflg,0 ; Is vt52 flag on?
jne vt0
jmp telnoe ; Don't do escape stuff if it's off.
vt0: call plup
mov ah,al ; Get the char.
cmp ah,'Z' ; Tell host our terminal type. [20a]
je vtiden ; [20a]
cmp ah,'Y' ; Special char - move cursor.
jne vt1
jmp movcur
vt1: cmp ah,'<' ; Start-ANSI? [17b start]
je vtexit ; Yes, ignore
cmp ah,'[' ; An ANSI command?
je vtansi ; Yes, do it
cmp ah,'@' ; Insert characters?
jne vtnins
mov incmod,1
jmp telnoe
vtnins: cmp ah,'p' ; Inverse?
jne vtninv
jmp vtinvi
vtninv: cmp ah,'q' ; Normal?
jne vtnino
jmp vtinvo ; [17b end]
vtnino: cmp ah,'A' ; Less than an 'A'?
jl vtig ; Yes - ignore.
cmp ah,'O'+1 ; Greater than 'O'? [17b]
jns vtig ; Yes - ignore.
mov al,'A'
sub ah,al ; Else make into index.
shl ah,1
mov bx,offset ttab ; Load base addr of table.
mov cl,ah ; Move a into cx.
mov ch,00H ; Zero out high byte.
add bx,cx ; Double add index+offset.
mov bx,[bx] ; Get address of routine to call.
jmp bx
vtig: ; Ignore escape sequence.
push ax ; Push the char to be output.
mov dl,esc ; Load an escape.
mov ah,conout ; The function code
int dos ; and the syscal.
pop ax ; Restore the character
mov dl,ah ; and move to output register.
mov ah,conout ; The function
int dos ; and the syscall.
ENDIF
vtexit: jmp telnoe ; Return home. [17b]
; Used for terminal-type querying programs. [20a]
IF ibmpc
vtiden: mov ah,ESC ; Respond with "ESC / K".
call outchr
jmp telnoe ; If failed, just forget the rest.
mov ah,"/"
call outchr
jmp telnoe
mov ah,"K"
call outchr
jmp telnoe ; And return even if failed.
jmp telnoe
ENDIF
; ANSI Insert/Delete Line. [17b start, 20g]
IF ibmpc
vtansi: call plup
cmp al,'?'
je vtanso
sub al,30H
mov temp,ax
call plup
cmp al,"9"
jg vtans1
sub al,30H
mov temp2,ax
mov ax,temp
mov dl,10
mul dl
add ax,temp2
mov temp,ax
call plup
vtans1: cmp al,'L'
jne vtans2
mov ah,3 ; Get cursor position
mov bh,0
int bios
mov temp1,dx
mov cx,dx ; Do a N-line scroll
mov cl,0
mov dx,184FH
mov ax,temp
mov ah,7
mov bh,7
int bios
jmp vtans3
vtans2: cmp al,'M'
jne vtans4
mov ah,3
mov bh,0
int bios
mov temp1,dx
mov ax,temp
mov ah,6
mov cx,dx
mov dx,184FH
mov bh,7
int bios
vtans3: mov dx,temp1 ; Restore cursor position
mov dl,0
mov ah,2
mov bh,0
int bios
vtans4: jmp telnoe
vtanso: call plup
call plup
jmp telnoe
vtinvi: mov curatt,0070H ; Reverse video
jmp telnoe
vtinvo: mov curatt,0007H ; Normal video
jmp telnoe ; [17b end]
TELESC ENDP
ENDIF
IF ibmpc
TEL PROC NEAR
movcur: call plup
sub al,32
mov dh,al
mov temp,dx ; Save row position here.
call plup
mov dx,temp ; Restore
sub al,32 ; Comes with 37Q added on (& starts at 1).
mov dl,al
mov bh,0
mov ah,2
int bios
jmp telnoe
curup: mov ah,3 ; Cursor up function.
mov bh,0
int bios
cmp dh,0
je cup0
sub dh,1
mov ah,2
int bios
cup0: jmp telnoe
curdwn: mov ah,3 ; Cursor down.
mov bh,0
int bios
cmp dh,24
je cdn0
add dh,1
mov ah,2
int bios
cdn0: jmp telnoe
currt: mov ah,3 ; Cursor right.
mov bh,0
int bios
cmp dl,79
je crt0
add dl,1
mov ah,2
int bios
crt0: jmp telnoe
curlft: mov ah,3 ; Cursor left.
mov bh,0
int bios
cmp dl,0
je clt0
sub dl,1
mov ah,2
int bios
clt0: jmp telnoe
curskp: jmp vtig ; Ignore for now.
curclr: call locate ; Home the cursor [15]
jmp curscr ; And clear the screen [15]
curhm: call locate
jmp telnoe
curscr: mov ah,3 ; Clear to end of screen.
mov bh,0
int bios
cmp dx,0
jne csr0
call cmblnk
jmp telnoe
csr0: cmp dl,0
je csr1
push dx
call clreol
pop dx
add dh,1
mov dl,0
csr1: mov cx,dx
mov dx,184FH
mov bh,7
; mov al,25
; sub al,ch
mov al,0
mov ah,7
int bios
jmp telnoe
curln: call clreol ; One routine to clear to EOL. [19a]
jmp telnoe
inslin: mov ah,3 ; Get cursor position.
mov bh,0
int bios
mov temp,dx ; Save here.
mov cx,dx
mov cl,0 ; Start at beginning of row.
mov dx,184FH ; End at lower corner of screen.
mov ax,0701H
mov bh,7
int bios ; Scroll down one line.
mov dx,temp ; Get back where we were.
mov dl,0
mov ah,2
mov bh,0
int bios
jmp telnoe
dellin: mov ah,3
mov bh,0
int bios ; Get current cursor position.
mov temp,dx ; Remember the place.
mov ax,0601H ; Scroll up one line.
mov cx,dx
mov cl,0 ; Start at beginning of row.
mov dx,184FH
mov bh,7
int bios
mov dx,temp
mov dl,0
mov ah,2
mov bh,0
int bios
jmp telnoe
; Delete character. [17b start]
delchr: mov ah,3 ; Get cursor position
mov bh,0
int bios
mov temp,dx
mov ah,1 ; Turn off cursor
mov ch,20H
int bios
delch1: mov ah,2 ; Position to col M+1
inc dl
int bios
mov ah,8 ; Get char/attr
int bios
mov cx,ax ; Save it
dec dl ; Position to col M
mov ah,2
int bios
mov ah,9 ; Write char/attr
mov al,cl
mov bl,ch
mov cx,1
int bios
inc dl ; Next column
cmp dl,79 ; About to write to col 80?
jne delch1 ; No
mov ah,2 ; Position to col 80
int bios
mov ah,9 ; Write char/attr
mov al,' '
int bios
mov ah,2 ; Reset cursor
mov dx,temp
int bios
mov ah,1
mov cx,0B0CH
int bios
jmp telnoe
; Cancel Insert Character mode
insmox: mov incmod,0
jmp telnoe ; [17b end]
TEL ENDP
; Common routine to clear to end-of-line. [19a]
CLREOL PROC NEAR
mov ah,3 ; Clear to end of line.
mov bh,0
int bios ; Get current cursor position
mov cx,dx
mov dl,79
mov ah,7
mov al,0
mov bh,7
int bios
ret
CLREOL ENDP
ENDIF
; This is the SET command.
SETCOM PROC NEAR
mov dx,offset settab ; Parse a keyword from the set table.
mov bx,offset sethlp
mov ah,cmkey
call comnd
jmp r
call bx
jmp rskp
SETCOM ENDP
; This is the ESCAPE character SET subcommand. [6 start]
ESCAPE PROC NEAR
call cmgtch ; Get a char.
cmp ah,0
jns es1 ; Terminator or no?
and ah,7FH ; Turn off minus bit.
cmp ah,'?'
jne es0
mov dx,offset eschlp
mov ah,prstr
int dos
mov dx,offset crlf
int dos
mov dx,offset kerm
int dos
mov bx,cmdptr
mov al,'$'
mov [bx],al
mov dx,offset cmdbuf
int dos
dec cmcptr ; Ignore dollar sign.
dec cmccnt
mov cmaflg,0
jmp repars
es0: mov ah,prstr
mov dx,offset ermes3
int dos
ret
es1: mov temp,ax
call cmcfrm
jmp es0
nop ; Take up 3 bytes.
mov ax,temp
mov escchr,ah ; Save new value.
ret
ESCAPE ENDP ; [6 end]
; This is the End-of-line character SET subcommand. [5 start]
EOLSET PROC NEAR
call cmgtch ; Get the first char into AH.
cmp ah,0
jns eol1
cmp ah,0BFH ; Question mark?
je eol4
jmp eol3
eol1: sub ah,030H ; Digit --> real number.
mov temp,ax ; Save the input.
call cmcfrm
jmp eol0 ; Got a char.
mov ax,0
mov bx,temp
jmp eol2
eol0: sub ah,030H ; Digit --> real number.
mov temp1,ax
call cmcfrm
jmp eol3 ; Too many chars.
mov bx,temp1
mov ax,temp
xchg al,ah
mov ah,0
eol2: mov temp,ax ; Save our registers.
mov temp1,bx
call cmcfrm
jmp eol3
mov bx,temp1
mov ax,temp
mov temp2,10 ; Get numerical value of char.
mul temp2
add al,bh
mov ah,0
cmp al,0
jl eol3
cmp al,1FH
jg eol3
mov seol,al ; Use new eol char.
ret
eol3: mov ah,prstr
mov dx,offset eolerr ; Bad end-of-line char
int dos
jmp prserr
eol4: mov ah,prstr
mov dx,offset eolhlp
int dos
mov dx,offset crlf
int dos
mov dx,offset kerm
int dos
mov bx,cmdptr
mov al,'$'
mov [bx],al
mov dx,offset cmdbuf
int dos
dec cmcptr ; Don't count the dollar sign.
dec cmccnt ; Or the question mark.
mov cmaflg,0 ; Check for more input.
jmp repars
EOLSET ENDP ; [5 end]
; This is the LOCAL echo SET subcommand.
LCAL PROC NEAR
mov dx,offset ontab
mov bx,offset onhlp
mov ah,cmkey
call comnd
jmp r
push bx ; Save the parsed value.
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
pop bx
mov ecoflg,bl ; Set the local echo flag.
ret
LCAL ENDP
; This is the VT52 emulation SET subcommand.
IF ibmpc
VT52EM PROC NEAR
mov dx,offset ontab
mov bx,offset onhlp
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
pop bx
mov vtflg,bl ; Set the VT52 emulation flag.
ret
VT52EM ENDP
ENDIF
; This is the SET subcommand to choose between COM1 and COM2. [19b]
IF ibmpc
COMSET PROC NEAR
mov dx,offset comptab
mov bx,offset comphlp
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
pop bx
mov comflg,bl ; Set the comm port flag.
call dobaud ; Set the baud rate for the port. [19a]
cmp comflg,1 ; Using Com 1?
jne coms0 ; Nope.
mov mddat,MDMDAT1 ; Set COM1 defaults.
mov mdstat,MDMSTS1
mov mdcom,MDMCOM1
mov mddis,MDMINTC
mov mden,MDMINTO
mov mdmeoi,EOICOM
mov mdintv,MDMINTV
ret
coms0: mov mddat,MDMDAT2 ; Set COM2 defaults.
mov mdstat,MDMSTS2
mov mdcom,MDMCOM2
mov mddis,MDINTC2
mov mden,MDINTO2
mov mdmeoi,EOICOM2
mov mdintv,MDINTV2
ret
COMSET ENDP
ENDIF
; This is the SET IBM command.
IBMSET PROC NEAR
mov dx,offset ontab
mov bx,offset onhlp
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
pop bx
mov ibmflg,bl ; Set the IBM flag.
cmp bl,0 ; Turning on or off? [12 start]
je ibmst1 ; If off, set parity & local echo to defaults.
mov ah,ibmpar ; Set IBM parity.
mov al,1 ; Set local echo on.
jmp ibmst2
ibmst1: mov ah,defpar ; Reset parity to default.
mov al,0 ; Turn off local echo.
ibmst2: mov parflg,ah ; Set parity.
mov ecoflg,al ; And local echo. [12 end]
xor al,01H ; 01 -> 00, 00 -> 01. [19c]
mov delflg,al ; BS -> DEL or BS -> BS. [19c]
ret
IBMSET ENDP
; This is the SET File-Warning command.
FILWAR PROC NEAR
mov dx,offset ontab
mov bx,offset onhlp
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
pop bx
mov flwflg,bl ; Set the IBM flag.
ret
FILWAR ENDP
; This is the SET aborted-file command. [20d]
ABFSET PROC NEAR
mov dx,offset abftab
mov bx,offset abfhlp
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
pop bx
mov abfflg,bl ; Set the aborted file flag.
ret
ABFSET ENDP
; This is the SET Parity command. [10 start]
SETPAR PROC NEAR
mov dx,offset partab
mov bx,offset parhlp
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
pop bx
mov parflg,bl ; Set the parity flag.
ret
SETPAR ENDP ; [10 end]
; Sets debugging mode on and off.
DEBST PROC NEAR
mov dx,offset ontab
mov bx,offset onhlp
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
pop bx
mov debug,bl ; Set the IBM flag.
ret
DEBST ENDP
; Turn bell on or off. [17a start]
BELLST PROC NEAR
mov dx,offset ontab
mov bx,offset onhlp
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd
jmp r
pop bx
mov belflg,bl
ret
BELLST ENDP ; [17a end]
; Function to set BS -> BS or BS -> DEL. [19c]
BSSET PROC NEAR
mov dx,offset BStab
mov bx,offset BShlp
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
pop bx
mov delflg,bl ; Set backspace/delete flag.
ret
BSSET ENDP
; This function sets the baud rate.
BAUDST PROC NEAR
mov dx,offset bdtab
mov bx,offset bdhlp
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get one.
pop bx
IF ibmpc
mov baud,bx ; Set the IBM flag.
call dobaud ; Use common code. [19a]
ENDIF
IF Z100
mov baud,bl ; Remember baud rate. [20g]
mov bx,ds ; Set up pointer to config info
mov es,bx ; . . .
mov bx,offset auxcnf ; . . .
mov ah,chr_control ; Function is control
mov al,chr_cfsu ; Subfunction is set new config
call bios_auxfunc ; Set the configuration
ENDIF
ret
BAUDST ENDP
; Only keep one copy of the code that sets the baud rate. [19a]
DOBAUD PROC NEAR
IF ibmpc
mov dx,mdcom ; LCR -- Initialize baud rate. [19b]
in al,dx
mov bl,al
or ax,80H
out dx,al
mov dx,mddat ; [19b]
mov ax,baud
out dx,al
inc dx
mov al,ah
out dx,al
mov dx,mdcom ; [19b]
mov al,bl
out dx,al
ENDIF
IF Z100
mov bx,ds ; Set up pointer to config info
mov es,bx ; . . .
mov bx,offset auxcnf ; . . .
mov ah,chr_status ; Get the function code
mov al,chr_sfgc ; And the subfunction to get config
call bios_auxfunc ; Get the block
ENDIF
ret
DOBAUD ENDP
; This is the STATUS command.
STATUS PROC NEAR
call stat0
jmp r
jmp rskp
STATUS ENDP
STAT0 PROC NEAR
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
stat01: mov dx,offset locst ; Assume local echo on.
cmp ecoflg,0 ; Is the local echo flag on?
jnz stat1
mov dx,offset remst ; If not say so.
stat1: mov ah,prstr ; Print it.
int dos
IF ibmpc
mov dx,offset vtemst ; Get address of the VT52 emulation string.
cmp vtflg,0 ; Is the VT52 emulation flag on?
jnz stat2
mov dx,offset novtst ; If not say so.
stat2: mov ah,prstr ; Print it.
int dos
mov dx,offset cm1st ; Assume we're using COM1. [19b start]
cmp comflg,1 ; Are we?
je stat2a ; Yup.
mov dx,offset cm2st ; We're using COM2.
stat2a: mov ah,prstr
int dos ; [19b end]
ENDIF
mov dx,offset ibmst ; Is IBM flag on?
cmp ibmflg,0
jnz stat3
mov dx,offset noibm ; Say it's not.
stat3: mov ah,prstr
int dos
mov dx,offset deboff ; Assume debug mode is off.
cmp debug,0
je stat4
mov dx,offset debon
stat4: mov ah,prstr
int dos
mov dx,offset flwon ; Assume file-warning on.
cmp flwflg,0
jne stat5
mov dx,offset flwoff
stat5: mov ah,prstr
int dos
mov dx,offset pnonst ; Assume no parity. [10 start]
cmp parflg,parnon
je stat6
mov dx,offset pmrkst ; Mark parity?
cmp parflg,parmrk
je stat6
mov dx,offset pevnst ; Maybe it's even parity.
cmp parflg,parevn
je stat6
mov dx,offset poddst ; Odd parity?
cmp parflg,parodd
je stat6
mov dx,offset pspcst
stat6: mov ah,prstr
int dos ;[10 end]
mov dx,offset belon ; Tell if bells ring at end. [17a start - DT]
cmp belflg,0
jne stat7
mov dx,offset beloff ; No bells.
stat7: mov ah,prstr
int dos ; That's it. [17a end - DT]
mov dx,offset abfdst ; Do we discard file if abort? [20d start]
cmp abfflg,1
je stat8
mov dx,offset abfkst ; Keep what we received so far.
stat8: int dos ; [20d end]
mov dx,offset bkdel ; Is backarrow BS or DEL... [19c start]
cmp delflg,1 ; Is it delete?
je stat9 ; Yup.
mov dx,offset bkbs ; It's a backspace.
stat9: int dos ; Tell the user. [19c end]
mov dx,offset eolst ; Tell the end-of-line char used. [5 start]
mov ah,prstr
int dos
mov ah,conout
mov dl,seol
add dl,40H
int dos ; [5 end]
mov ah,prstr
mov dx,offset escmes ; Print escape character. [6]
int dos
call escprt
call baudprt ; Print the baud rate. [19a]
mov dx,offset cmcrlf ; Get the address of a crlf.
mov ah,prstr ; Print it.
int dos
jmp rskp
STAT0 ENDP
; Print information on the baud rate. [19a]
BAUDPRT PROC NEAR
mov dx,offset b48st ; Assume 4800 baud.
cmp baud,B4800
jnz bdprt0
jmp bdprt2
bdprt0: mov dx,offset b12st
cmp baud,B1200
jnz bdprt1
jmp bdprt2
bdprt1: mov dx,offset b18st
cmp baud,B1800
jz bdprt2
mov dx,offset b24st
cmp baud,B2400
jz bdprt2
mov dx,offset b96st
cmp baud,B9600
jz bdprt2
mov dx,offset b03st
IF ibmpc
jmp bdprt2
ENDIF
IF Z100
cmp baud,B0300
jz bdprt2
mov dx,offset b04st
cmp baud,B00455
jz bdprt2
mov dx,offset b05st
cmp baud,B0050
jz bdprt2
mov dx,offset b07st
cmp baud,b0075
jz bdprt2
mov dx,offset b11st
cmp baud,B0110
jz bdprt2
mov dx,offset b13st
cmp baud,B01345
jz bdprt2
mov dx,offset b15st
cmp baud,B0150
jz bdprt2
mov dx,offset b06st
cmp baud,B0600
je bdprt2
mov dx,offset b20st
cmp baud,B2000
jz bdprt2
mov dx,offset b19st
cmp baud,B19200
jz bdprt2
mov dx,offset b38st
ENDIF
bdprt2: mov ah,prstr
int dos
ret
BAUDPRT ENDP
; Utility routines
; Jumping to this location is like retskp. It assumes the instruction
; after the call is a jmp addr.
RSKP PROC NEAR
pop bp
add bp,3
push bp
ret
RSKP ENDP
; Jumping here is the same as a ret.
R PROC NEAR
ret
R ENDP
; This routine prints the number in AX on the screen. (Thanks to Jeff
; Damens). No longer used but keep around just in case.
;NOUT PROC NEAR
; push bx ; Save some stuff.
; push cx
; push dx
; push ax
; mov bh,0 ; Don't print leading zeros.
; and ah,0F0H ; Only want high order nibble.
; mov cl,4
; shr ah,cl
; call pdig ; Print the digit.
; pop ax ; Restore argument.
; and ah,0FH ; Just the low order nibble.
; call pdig
; mov ah,al
; and ah,0F0H ; Only want high order nibble.
; mov cl,4
; shr ah,cl
; call pdig ; Print the digit.
; mov ah,al
; and ah,0FH ; Just the low order nibble.
; mov bh,0FFH ; Make sure at least one zero is printed.
; call pdig
; pop dx ; Restore some stuff.
; pop cx
; pop bx
; ret
;NOUT ENDP
; Print the number in AX on the screen in decimal rather that hex. [19a]
NOUT PROC NEAR
push ax
push dx
mov temp,10 ; Divide quotient by 10.
cwd ; Convert word to doubleword.
div temp ; AX <-- Quo, DX <-- Rem.
cmp ax,0 ; Are we done?
jz nout0 ; Yes.
call nout ; If not, then recurse.
nout0: add dl,'0' ; Make it printable.
mov temp,ax
mov ah,conout
int dos
mov ax,temp
pop dx
pop ax
ret
NOUT ENDP
; print the digit in register AH
PDIG PROC NEAR
push ax ; Save it.
cmp ah,0
jne pdig2
cmp bh,0
jne pdig2
pop ax
ret
pdig2: mov bh,0FFH ; Set the print zero flag.
cmp ah,10 ; Do we use digits or a-f?
jl usedig ; Digit.
add ah,'A'-10 ; Compute digit
jmp havdig ; and proceed.
usedig: add ah,'0' ; Convert to digit
havdig: mov dl,ah
mov ah,conout
int dos
pop ax
ret
PDIG ENDP
; This set of routines provides a user oriented way of parsing
; commands. It is similar to that of the COMND JSYS in TOPS-20.
; This routine prints the prompt in DE and specifies the reparse
; address.
PROMPT PROC NEAR
pop bx ; Get the return address.
push bx ; Put it on the stack again.
mov cmrprs,bx ; Save as addr to go to on reparse.
mov bx,0 ; Clear out register.
add bx,sp ; Get the present stack pointer.
mov cmostp,bx ; Save for later restoral.
mov cmprmp,dx ; Save pointer to the prompt.
mov bx,offset cmdbuf
mov cmcptr,bx ; Initialize the command pointer.
mov cmdptr,bx
mov ah,0
mov cmaflg,ah ; Zero the flags.
mov cmccnt,ah
mov cmsflg,0FFH
mov ah,prstr
mov dx,offset cmcrlf
int dos
mov ah,prstr ; Print the prompt.
mov dx,cmprmp
int dos
ret
PROMPT ENDP
; This address is jumped to on reparse.
PARSE PROC NEAR
repars: mov sp,cmostp ; new sp <-- old sp
mov bx,offset cmdbuf
mov cmdptr,bx
mov ah,0FFH
mov cmsflg,ah
mov bx,cmrprs ; Get the reparse address.
call bx ; Go there.
; This address can be jumped to on a parsing error.
prserr: mov sp,cmostp ; Set new sp to old one.
mov bx,offset cmdbuf
mov cmcptr,bx ; Initialize the command pointer.
mov cmdptr,bx
mov ah,0
mov cmaflg,ah ; Zero the flags.
mov cmccnt,ah
mov cmsflg,0FFH
mov ah,prstr
mov dx,offset cmcrlf
int dos
mov ah,prstr ; Print the prompt.
mov dx,cmprmp ; Get the prompt.
int dos
; Instead return to before the prompt call.
mov bx,cmrprs
call bx
PARSE ENDP
; This routine parses the specified function in AH. Any additional
; information is in DX and BX.
; Returns +1 on success
; +4 on failure (assumes a JMP follows the call)
CMND PROC NEAR
comnd: mov cmstat,ah ; Save what we are presently parsing.
call cminbf ; Get chars until an action or a erase char.
mov ah,cmstat ; Restore 'ah' for upcoming checks.
cmp ah,cmcfm ; Parse a confirm?
jz cmcfrm ; Go get one.
cmp ah,cmkey ; Parse a keyword?
jnz cm1
jmp cmkeyw ; Try and get one.
cm1: cmp ah,cmifi ; Parse an input file spec?
jnz cm2
jmp cmifil ; Go get one.
cm2: cmp ah,cmofi ; Output file spec?
jnz cm3
jmp cmofil ; Go get one.
cm3: cmp ah,cmtxt ; Parse arbitrary text. [8]
jnz cm4
jmp cmtext
cm4: mov ah,prstr ; Else give error.
mov dx,offset cmer00 ; "?Unrecognized COMND call"
int dos
ret
; This routine gets a confirm.
cmcfrm: call cmgtch ; Get a char.
cmp ah,0 ; Is it negative (a terminator; a space or
; a tab will not be returned here as they
; will be seen as leading white space.)
js cmcfr0
ret ; If not, return failure.
cmcfr0: and ah,7FH ; Turn off the minus bit.
cmp ah,esc ; Is it an escape?
jne cmcfr2
mov ah,conout
mov dl,bell ; Get a bell.
int dos
mov ah,0
mov cmaflg,ah ; Turn off the action flag.
mov bx,cmcptr ; Move the pointer to before thee scape.
dec bx
mov cmcptr,bx
mov cmdptr,bx
dec cmccnt ; Decremrnt the char count.
jmp cmcfrm ; Try again.
cmcfr2: cmp ah,'?' ; Curious?
jne cmcfr3
mov ah,prstr ; Print something useful.
mov dx,offset cmin00
int dos
mov ah,prstr
mov dx,offset cmcrlf ; Print a crlf.
int dos
mov ah,prstr
mov dx,cmprmp ; Reprint the prompt.
int dos
mov bx,cmdptr ; Get the pointer into the buffer.
mov ah,'$' ; Put a $ there for printing.
mov [bx],ah
mov bx,cmcptr
dec bx ; Decrement & save the buffer pointer.
mov cmcptr,bx
mov ah,prstr
mov dx,offset cmdbuf
int dos
mov ah,0 ; Turn off the action flag.
mov cmaflg,ah
jmp repars ; Reparse everything.
cmcfr3: cmp ah,ff ; Is it a form feed?
jne cmcfr4
call cmblnk ; If so blank the screen.
cmcfr4: jmp rskp
; This routine parses a keyword from the table pointed
; to in DX. The format of the table is as follows:
;
; addr: db n ; Where n is the # of entries in the table.
; db m ; M is the size of the keyword.
; db 'string$' ; Where string is the keyword.
; dw ab ; Where ab is data to be returned.
;
; The keywords must be in alphabetical order.
cmkeyw: mov cmhlp,bx ; Save the help.
mov cmptab,dx ; Save the beginning of keyword table.
mov bx,dx
mov ch,[bx] ; Get number of entries in table.
inc bx
mov dx,cmdptr ; Save command pointer.
mov cmsptr,dx ; Save pointer's here.
cmky1: cmp ch,0 ; Any commands left to check?
jne cmky2
; mov ah,prstr ; [19e]
; mov dx,offset cmer04 ; Complain. [1] [19e]
; int dos ; [19e]
ret ; Fail if not.
cmky2: dec ch
mov cl,0 ; Keep track of how many chars read in so far.
call cmgtch ; Get a char.
cmp ah,0 ; Do we have a terminator?
jns cmky2x
jmp cmky4 ; Negative number means we do.
cmky2x: inc bx ; Point to first letter of keyword.
inc cl ; Read in another char.
mov al,[bx]
cmp ah,'a' ; Less than a?
jl cmky21 ; If so, don't capitalize.
cmp ah,'z'+1 ; More than z?
jns cmky21
and ah,137O ; Capitalize the letter.
cmky21: cmp ah,al
je cmky3
jg cmky2y
jmp cmky41 ; Fail if ah preceeds al alphabetically.
cmky2y: jmp cmky6 ; Not this keyword - try the next.
cmky3: inc bx ; We match here, how 'bout next char?
mov al,[bx]
cmp al,'$' ; End of keyword?
jne cmky3x
jmp cmky7 ; Succeed.
cmky3x: mov dl,al ; Save al's char here.
call cmgtch
inc cl ; Read in another char.
mov al,dl
cmp ah,'a'
jl cmky31
cmp ah,'z'+1
jns cmky31
and ah,137O
cmky31: cmp ah,9BH ; Escape Recognition (escape w/minus bit on)?
je cmky3y
cmp ah,0BFH ; A question mark? [3]
je cmky3y
cmp ah,0A0H ; A space?
je cmky3y
cmp ah,8DH ; Carriage return?
je cmky3y
jmp cmky38
cmky3y: mov cmkptr,bx ; Save bx here.
mov cmsiz,cx ; Save size info.
mov cmchr,ah ; Save char for latter.
call cmambg ; See if input is ambiguous or not.
jmp cmky32 ; Succeeded (not ambiguous).
mov ah,cmchr
cmp ah,9BH ; Escape?
je cmky3z
jmp cmky41 ; Fail.
cmky3z: mov ah,conout ; Else, ring a bell.
mov dl,bell
int dos
mov bx,cmcptr ; Move pointer to before the escape.
dec bx
mov cmcptr,bx
mov cmdptr,bx
dec cmccnt ; Decrement char count.
mov bx,cmkptr ; Failed - pretend user never typed ....
mov cx,cmsiz ; ... in a char.
dec cl ; Don't count the escape.
dec bx
mov cmaflg,0 ; Reset the action flag.
jmp cmky3 ; Keep checking.
cmky32: mov cx,cmsiz ; Restore info.
mov bx,cmkptr ; Our place in the keyword table.
cmp cmchr,0A0H ; Space?
je cmky35
cmp cmchr,0BFH ; Question mark? [3]
je cmky35
cmp cmchr,8DH ; Carriage return?
je cmky35
dec cmcptr ; Pointer into buffer of input.
mov dx,cmcptr
cmky33: mov ah,[bx] ; Get next char in keyword.
cmp ah,'$' ; Are we done yet?
jz cmky34
mov di,dx
mov [di],ah
inc bx
inc dx
inc cmccnt
jmp cmky33
cmky34: mov ah,' '
mov di,dx
mov [di],ah ; Put a blank in the buffer.
inc dx
mov cx,cmcptr ; Remember where we were (for printing below).
mov cmcptr,dx ; Update our pointers.
mov cmdptr,dx
mov ah,'$'
mov di,dx
mov [di],ah ; Add '$' for printing.
mov ah,prstr
mov dx,cx ; Point to beginning of filled in data.
int dos
inc bx ; Point to address we'll need.
mov bx,[bx]
mov cmaflg,0 ; Turn off action flag.
jmp rskp
cmky35: inc bx
mov ah,[bx] ; Find end of keyword.
cmp ah,'$'
jne cmky35
inc bx
mov bx,[bx] ; Address of next routine to call.
; mov cmaflg,0 ; Zero the action flag.
jmp rskp
cmky38: cmp ah,al
jne cmky6 ; Go to end of keyword and try next.
jmp cmky3
cmky4: and ah,7FH ; Turn off minus bit.
cmp ah,'?' ; Need help?
je cmky5
cmp ah,' ' ; Just a space - no error.
je cmky51
cmp ah,cr
je cmky51
cmp ah,tab
je cmky51
cmp ah,esc ; Ignore escape?
je cmky43
cmky41: mov ah,prstr
mov dx,offset cmer03
int dos
jmp prserr ; Parse error - give up.
cmky43: mov ah,conout ; Ring a bell.
mov dl,bell
int dos
mov bx,cmcptr
dec bx
mov cmcptr,bx
mov cmdptr,bx
dec cmccnt ; Don't count the escape.
mov cmaflg,0 ; Reset action flag.
inc ch ; Account for a previous 'dec'.
jmp cmky1 ; Start over.
cmky5: mov ah,prstr
mov dx,cmhlp ; Print the help text.
int dos
mov dx,offset crlf
int dos
mov dx,offset kerm
int dos
mov bx,cmdptr ; Get pointer into buffer.
mov al,'$'
mov [bx],al ; Add dollar sign for printing.
mov dx,offset cmdbuf
int dos
dec cmcptr ; Don't keep it in the buffer.
dec cmccnt ; Don't conut it.
mov cmaflg,0 ; Turn off the action flag.
jmp repars
cmky51: jmp prserr
cmky6: inc bx ; Find end of keyword.
mov al,[bx]
cmp al,'$'
jne cmky6
inc bx ; Beginning of next command.
inc bx
inc bx
mov dx,cmsptr ; Get old cmdptr.
mov cmdptr,dx ; Restore.
mov cmsflg,0FFH
jmp cmky1 ; Keep trying.
cmky7: call cmgtch ; Get char.
cmp ah,0
js cmky71 ; Ok if a terminator.
dec bx
jmp cmky6 ; No match - try next keyword.
cmky71: inc bx ; Get necessary data.
mov bx,[bx]
cmp ah,9BH ; An escape?
jne cmky72
mov ah,prstr
mov dx,offset prsp ; Print a space.
int dos
mov di,cmcptr
dec di
mov ah,20H
mov [di],ah ; Replace escape char with space.
mov cmaflg,0
mov cmsflg,0FFH ; Pretend they typed a space.
cmky72: jmp rskp
; See if keyword is unambiguous or not from what the user has typed in.
cmambg: cmp ch,0 ; Any keywords left to check?
jne cmamb0
ret ; If not then not ambiguous.
cmamb0: inc bx ; Go to end of keyword ...
mov al,[bx] ; So we can check the next one.
cmp al,'$'
jne cmamb0
add bx,4 ; Point to start of next keyword.
dec cl ; Don't count escape.
mov dx,cmsptr ; Buffer with input typed by user.
cmamb1: mov ah,[bx] ; Keyword char.
mov di,dx
mov al,[di] ; Input char.
cmp al,'a' ; Do capitalizing.
jl cmam11
cmp al,'z'+1
jns cmam11
and al,137O
cmam11: cmp ah,al ; Keyword bigger than input (alphabetically)?
jle cmamb2 ; No - keep checking.
ret ; Yes - not ambiguous.
cmamb2: inc bx ; Advance one char.
inc dx
dec cl
jnz cmamb1
jmp rskp ; Fail - it's ambiguous.
cmifil: mov bx,dx ; Get the fcb address in bx.
mov cmfcb,bx ; Save it.
mov ch,0 ; Initialize char count.
mov ah,0
mov [bx],ah ; Set the drive to default to current.
inc bx
mov cmfcb2,bx
mov cl,' '
cmifi0: mov [bx],cl ; Blank the FCB.
inc bx
inc ah
cmp ah,0BH ; Twelve?
jl cmifi0
cmifi1: call cmgtch ; Get another char.
cmp ah,0 ; Is it an action character.
jns cmifi2
and ah,7FH ; Turn off the action bit.
cmp ah,'?' ; A question mark?
jne cmif12
mov al,0
mov cmaflg,al ; Blank the action flag.
dec cmcptr ; Decrement the buffer pointer.
dec cmccnt ; Decrement count.
; jmp cmifi8 ; Treat like any other character.
mov ah,prstr
mov dx,offset filhlp ; Help message.
int dos
mov dx,offset crlf
int dos
mov dx,offset kerm
int dos
mov bx,cmdptr
mov al,'$'
mov [bx],al ; Put in dollar sign for printing.
mov dx,offset cmdbuf
int dos
jmp repars
cmif12: cmp ah,esc ; An escape?
jne cmif13
mov ah,0
mov cmaflg,ah ; Turn off the action flag.
mov ah,conout
mov dl,bell
int dos ; Ring the bell.
mov bx,cmcptr ; Move the pointer to before the escape.
dec bx
mov cmcptr,bx
mov cmdptr,bx
dec cmccnt ; Decrement char count.
jmp repars
cmif13: mov ah,ch ; It must be a terminator.
cmp ah,0 ; Test the length of the file name.
jnz cmf3x
jmp cmifi9 ; If zero complain.
cmf3x: cmp ah,0DH
js cmf3y
jmp cmifi9 ; If too long complain.
cmf3y: jmp rskp ; Otherwise we have succeeded.
cmifi2: cmp ah,'.'
jne cmifi3
inc ch
mov ah,ch
cmp ah,1H ; Any chars yet?
jnz cmf2x
jmp cmifi9 ; No, give error.
cmf2x: cmp ah,0AH ; Tenth char?
js cmf2y
jmp cmifi9 ; Past it, give an error.
cmf2y: mov dl,9H
mov dh,0
mov bx,cmfcb
add bx,dx ; Point to file type field.
mov cmfcb2,bx
mov ch,9H ; Say we've gotten nine.
jmp cmifi1 ; Get the next char.
cmifi3: cmp ah,':'
jne cmifi4
inc ch
cmp ch,2H ; Is it in right place for a drive?
je cmif3x
jmp cmifi9 ; If not, complain.
cmif3x: mov ch,0 ; Reset char count.
mov bx,cmfcb2
sub bx,1
mov ah,[bx] ; Get the drive name.
sub ah,'@' ; Get the drive number.
mov cmfcb2,bx
mov bx,cmfcb
mov [bx],ah ; Put it in the fcb.
jmp cmifi1
cmifi4: cmp ah,'*'
jne cmifi7
mov ah,ch
cmp ah,8H ; Is this in the name or type field?
jz cmifi9 ; If its where the dot should be give up.
jns cmifi5 ; Type.
mov cl,8H ; Eight chars.
jmp cmifi6
cmifi5: mov cl,0CH ; Three chars.
cmifi6: mov wldflg,0FFH ; Remember we had a wildcard.
mov bx,cmfcb2 ; Get a pointer into the FCB.
mov ah,'?'
mov [bx],ah ; Put a question mark in.
inc bx
mov cmfcb2,bx
inc ch
mov ah,ch
cmp ah,cl
jl cmifi6 ; Go fill in another.
jmp cmifi1 ; Get the next char.
cmifi7: cmp ah,03DH ; Equals sign (wildcard)?
jne cmif7x
mov ah,'?'
mov wldflg,0FFH ; Say we have a wildcard.
jmp cmifi8 ; Put into FCB.
cmif7x: cmp ah,'0'
jl cmif8x
cmp ah,'z'+1
jns cmif8x
cmp ah,'A' ; Don't capitalize non-alphabetics.
jl cmifi8
and ah,137O ; Capitalize.
cmifi8: mov bx,cmfcb2 ; Get the pointer into the FCB.
mov [bx],ah ; Put the char there.
inc bx
mov cmfcb2,bx
inc ch
jmp cmifi1
cmif8x: push es
mov cx,ds
mov es,cx ; Scan uses ES register.
mov di,offset spchar ; Special chars.
mov cx,20 ; Twenty of them.
mov al,ah ; Char is in al.
repnz scasb ; Search string for input char.
cmp cx,0 ; Was it there?
pop es
jnz cmifi8
cmifi9: mov ah,prstr
mov dx,offset cmer02
int dos
ret
cmofil: jmp cmifil ; For now, the same as CMIFI.
; Parse arbitrary text up to a CR. Put chars into data buffer sent to
; the host (pointed to by BX). Return updated pointer in BX and
; input size in AH.
cmtext: mov cmptab,bx ; Save pointer to data buffer. [8 start]
mov cl,0 ; Init the char count.
cmtxt1: call cmgtch ; Get a char.
cmp ah,0 ; Terminator?
jns cmtxt5 ; Nope, put into the buffer.
and ah,07FH
cmp ah,esc ; An escape?
jne cmtxt2
mov ah,conout
mov dl,bell ; Ring a bell.
int dos
mov cmaflg,0 ; Reset action flag.
dec cmcptr ; Move pointer to before the escape.
dec cmdptr
dec cmccnt ; Decrement count.
jmp cmtxt1 ; Try again.
cmtxt2: cmp ah,'?' ; Asking a question?
jz cmtxt3
cmp ah,ff ; Formfeed?
jne cmtx2x
call cmblnk
cmtx2x: mov ah,cl ; Return count in AH.
mov bx,cmptab ; Return updated pointer.
jmp rskp
cmtxt3: mov cmaflg,0 ; Reset action flag to zero.
cmtxt5: inc cl ; Increment the count.
mov bx,cmptab ; Pointer into destination array.
mov [bx],ah ; Put char into the buffer.
inc bx
mov cmptab,bx
jmp cmtxt1 ; [8 end]
cminbf: push dx
push bx
mov cx,dx ; Save value here too.
mov ah,cmaflg ; Is the action char flag set?
cmp ah,0
je cminb1
jmp cminb9 ; If so get no more chars.
cminb1: inc cmccnt ; Increment the char count.
mov ah,conin ; Get a char.
int dos
mov ah,al ; Keep char in 'ah'.
mov bx,cmcptr ; Get the pointer into the buffer.
mov [bx],ah ; Put it in the buffer.
inc bx
mov cmcptr,bx
cmp ah,25O ; Is it a ^U?
jne cminb2
cmnb12: mov ah,prstr
mov dx,offset clrlin
int dos
IF ibmpc
mov ax,0920H ; Write spaces.
mov bx,7 ; Clear the line.
mov cx,80
int bios
ENDIF
mov ah,prstr
mov dx,cmprmp ; Print the prompt.
int dos
mov bx,offset cmdbuf
mov cmcptr,bx ; Reset the point to the start.
mov cmccnt,0 ; Zero the count.
mov dx,cx ; Preserve original value of dx.
jmp repars ; Go start over.
cminb2: cmp ah,10O ; Or backspace?
jz cminb3
cmp ah,del ; Delete?
jne cminb4
mov ah,prstr ; Print the delete string.
mov dx,offset delstr
int dos
cminb3: mov ah,cmccnt ; Decrement the char count by two.
dec ah
dec ah
cmp ah,0 ; Have we gone too far?
jns cmnb32 ; If not proceed.
mov ah,conout ; Ring the bell.
mov dl,bell
int dos
jmp cmnb12 ; Go reprint prompt and reparse.
cmnb32: mov cmccnt,ah ; Save the new char count.
mov ah,prstr ; Erase the character.
mov dx,offset clrspc
int dos
mov bx,cmcptr ; Get the pointer into the buffer.
dec bx ; Back up in the buffer.
dec bx
mov cmcptr,bx
jmp repars ; Go reparse everything.
cminb4: cmp ah,'?' ; Is it a question mark.
jz cminb6
cmp ah,esc ; Is it an escape?
jz cminb8
cmp ah,cr ; Is it a carriage return?
jz cminb5
cmp ah,lf ; Is it a line feed?
jz cminb5
cmp ah,ff ; Is it a formfeed?
jne cminb7
call cmblnk
call locate
cminb5: mov ah,cmccnt ; Have we parsed any chars yet?
cmp ah,1
jnz cminb6
jmp prserr ; If not, just start over.
cminb6: mov ah,0FFH ; Set the action flag.
mov cmaflg,ah
jmp cminb9
cminb7: jmp cminb1 ; Get another char.
cminb8: mov ah,prstr ; Don't print the escape char.
mov dx,offset escspc
int dos
jmp cminb6
cminb9: pop bx
pop dx
ret
cmgtch: push cx
push bx
push dx
cmgtc1: mov ah,cmaflg
cmp ah,0 ; Is it set.
jne cmgt10
call cminbf ; If the action char flag is not set get more.
cmgt10: mov bx,cmdptr ; Get a pointer into the buffer.
mov ah,[bx] ; Get the next char.
inc bx
mov cmdptr,bx
cmp ah,' ' ; Is it a space?
jz cmgtc2
cmp ah,tab ; Or a tab?
jne cmgtc3
cmgtc2: mov ah,cmsflg ; Get the space flag.
cmp ah,0 ; Was the last char a space?
jne cmgtc1 ; Yes, get another char.
mov ah,0FFH ; Set the space flag.
mov cmsflg,ah
mov ah,' '
pop dx
pop bx
jmp cmgtc5
cmgtc3: mov al,0
mov cmsflg,al ; Zero the space flag.
pop dx
pop bx
cmp ah,esc
jz cmgtc5
cmp ah,'?' ; Is the user curious?
jz cmgtc4
cmp ah,cr
jz cmgtc4
cmp ah,lf
jz cmgtc4
cmp ah,ff
je cmgtc4
pop cx
ret ; Not an action char, just return.
cmgtc4: dec cmdptr
cmgtc5: or ah,80H ; Make the char negative to indicate
pop cx
ret ; it is a terminator.
CMND ENDP
; This routine blanks the screen.
CMBLNK PROC NEAR ; This is stolen from the IBM example.
IF ibmpc
mov cx,0
mov dx,184FH
mov bh,7
mov ax,600H
int bios
ENDIF
IF Z100
mov ah,prstr ; Get the function code
mov dx,offset clrscr ; Want to clear the screen
int dos ; Do it
ENDIF
ret
CMBLNK ENDP
; Cursor control.
LOCATE PROC NEAR
IF ibmpc
mov dx,0 ; Go to top left corner of screen.
mov bh,0
mov ah,2
int bios
ENDIF
IF Z100
mov ah,prstr ; Function is print string
mov dx,offset homcur ; Home cursor
int dos ; do it
ENDIF
ret
LOCATE ENDP
MAIN ENDS ; End of code section.
END START